1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
|
/****************************************************************
* *
* Copyright (c) 2011-2020 Fidelity National Information *
* Services, Inc. and/or its subsidiaries. All rights reserved. *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
* under a license. If you do not know the terms of *
* the license, please stop and do not read further. *
* *
****************************************************************/
#include "mdef.h"
#ifdef GTM_TRIGGER
#include "error.h"
#include "gdsroot.h" /* for gdsfhead.h */
#include "gdsbt.h" /* for gdsfhead.h */
#include "gdsfhead.h"
#include "gvcst_protos.h"
#include <rtnhdr.h>
#include "gv_trigger.h"
#include "gtm_trigger.h"
#include "trigger.h"
#include "min_max.h"
#include "filestruct.h" /* for INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED (FILE_INFO) */
#include "gdscc.h" /* needed for tp.h */
#include "gdskill.h" /* needed for tp.h */
#include "buddy_list.h" /* needed for tp.h */
#include "jnl.h" /* needed for tp.h */
#include "tp.h"
#include "op.h"
#include "op_tcommit.h"
#include "tp_frame.h"
#include "gvnh_spanreg.h"
#include "trigger_read_andor_locate.h"
#include "repl_msg.h" /* for gtmsource.h */
#include "gtmsource.h" /* for jnlpool_addrs_ptr_t */
GBLREF sgmnt_addrs *cs_addrs;
GBLREF sgmnt_data_ptr_t cs_data;
GBLREF gd_addr *gd_header;
GBLREF rtn_tabent *rtn_names, *rtn_names_end;
GBLREF tp_frame *tp_pointer;
GBLREF gv_key *gv_currkey;
GBLREF gd_region *gv_cur_region;
GBLREF sgm_info *sgm_info_ptr;
GBLREF jnlpool_addrs_ptr_t jnlpool;
LITREF mval literal_batch;
error_def(ERR_TRIGNAMENF);
/* Routine to locate the named trigger and if not loaded, to go ahead and load it.
*
* The following sitations can exist:
*
* 1. No trigger by the given name is loaded. For this situation, we need to locate and load the trigger.
* 2. Trigger is loaded. Note this routine does no validation of the trigger but just returns whatever is
* currently loaded.
*
* Note, this routine is for locating a trigger that is not to be run and merrily located so its embedded source
* can be made available. Other trigger related routines are:
*
* a. trigger_source_read_andor_verify() - Verifies has current trigger object (primary usage op_setbrk()).
* b. trigger_fill_xecute_buffer() - Same verification but makes sure source is available - typically used when
* trigger is about to be driven.
*
* Note this routine has similar components to trigger_source_read_andor_verify() and its subroutines so updates
* to that routine should also be check if they apply here and vice versa. This routine is lighter weight without
* the overhead of being in a transaction unless it has to load a trigger in which case it calls the full routine
* trigger_source_read_andor_verify(). Since a trigger's source is embedded in a trigger, we only need to locate
* the trigger to have access to the source for $TEXT() type services. The primary issue this separate mechanism
* solves is when an error occurs and trigger is on the M stack, error handling will attempt to locate the source
* line in the trigger where it was as part of filling in the $STACK() variable. The mini-transaction created by
* trigger_source_read_andor_verify() of course uses the critical section but that use, if the process is also
* holding a lock perhaps in use by another process holding the lock we need, creates a deadlock. So we avoid
* doing anything with triggers in the event of an error in this fashion.
*/
int trigger_locate_andor_load(mstr *trigname, rhdtyp **rtn_vec)
{
mstr_len_t origlen;
char *ptr, *ptr_beg, *ptr_top;
boolean_t runtime_disambiguator_specified;
gd_region *reg;
mstr regname, gbl;
mident rtn_name;
gd_region *save_gv_cur_region;
gv_key_buf save_currkey;
gv_namehead *gvt;
gv_namehead *save_gv_target;
gvnh_reg_t *gvnh_reg;
gv_trigger_t *trigdsc;
gvt_trigger_t *gvt_trigger;
rtn_tabent *rttabent;
sgm_info *save_sgm_info_ptr;
jnlpool_addrs_ptr_t save_jnlpool;
rhdtyp *rtn_vector;
sgmnt_addrs *csa, *regcsa;
sgmnt_data_ptr_t csd;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
assert(NULL != trigname);
assert((NULL != trigname->addr) && (0 != trigname->len));
if (NULL == gd_header)
gvinit();
DBGTRIGR((stderr, "trigger_locate_andor_load: Entered with $tlevel=%d, $trigdepth=%d\n",
dollar_tlevel, gtm_trigger_depth));
/*
* Input parameter "trigname" is of the form
* a) <21-BYTE-MAX-TRUNCATED-GBLNAME>#<AUTO-GENERATED-CNT>#[RUNTIME-DISAMBIGUATOR][/REGION-NAME] OR
* b) <28-BYTE-USER-SPECIFIED-TRIGNAME>#[RUNTIME-DISAMBIGUATOR][/REGION-NAME]
* where
* <21-BYTE-MAX-TRUNCATED-GBLNAME>#<AUTO-GENERATED-CNT> OR <28-BYTE-USER-SPECIFIED-TRIGNAME> is the
* auto-generated or user-specified trigger name we are searching for
* RUNTIME-DISAMBIGUATOR is the unique string appended at the end by the runtime to distinguish
* multiple triggers in different regions with the same auto-generated or user-given name
* REGION-NAME is the name of the region in the gld where we specifically want to search for trigger names
* [] implies optional parts
*
* Example usages are
* x# : trigger routine user-named "x"
* x#1# : trigger routine auto-named "x#1"
* x#1#A : trigger routine auto-named "x#1" but also runtime disambiguated by "#A" at the end
* x#/BREG : trigger routine user-named "x" in region BREG
* x#A/BREG : trigger routine user-named "x", runtime disambiguated by "#A", AND in region BREG
* x#1#/BREG : trigger routine auto-named "x#1" in region BREG
* x#1#A/BREG : trigger routine auto-named "x#1", runtime disambiguated by "#A", AND in region BREG
*/
/* First lets locate the trigger. Try simple way first - lookup in routine name table.
* But "find_rtn_tabent" function has no clue about REGION-NAME so remove /REGION-NAME (if any) before invoking it.
*/
regname.len = 0;
reg = NULL;
origlen = trigname->len; /* Save length in case need to restore it later */
for (ptr_beg = trigname->addr, ptr_top = ptr_beg + trigname->len, ptr = ptr_top - 1; ptr >= ptr_beg; ptr--)
{
/* If we see a '#' and have not yet seen a '/' we are sure no region-name disambiguator has been specified */
if ('#' == *ptr)
break;
if ('/' == *ptr)
{
trigname->len = ptr - trigname->addr;
ptr++;
regname.addr = ptr;
regname.len = ptr_top - ptr;
reg = find_region(®name); /* find region "regname" in "gd_header" */
if (NULL == reg)
{ /* Specified region-name is not present in current gbldir.
* Treat non-existent region name as if trigger was not found.
*/
ISSUE_TRIGNAMENF_ERROR_IF_APPROPRIATE(trigname);
return TRIG_FAILURE_RC;
}
break;
}
}
if (NULL != *rtn_vec)
{
rtn_vector = *rtn_vec;
rttabent = rtn_names;
} else if (find_rtn_tabent(&rttabent, trigname))
rtn_vector = rttabent->rt_adr;
else
rtn_vector = NULL;
DBGTRIGR((stderr, "trigger_locate_andor_load: routine was %sfound (1)\n", (NULL == rtn_vector)?"not ":""));
/* If we have the trigger routine header, do some validation on it, else keep looking */
SAVE_REGION_INFO(save_currkey, save_gv_target, save_gv_cur_region, save_sgm_info_ptr, save_jnlpool);
runtime_disambiguator_specified = ('#' != trigname->addr[trigname->len - 1]);
if (!runtime_disambiguator_specified && (NULL != reg))
{ /* Region-name has been specified and no runtime-disambiguator specified. Need to further refine the
* search done by find_rtn_tabent to focus on the desired region in case multiple routines with the same
* trigger name (but different runtime-disambiguators) exist.
*/
rtn_name.len = MIN(trigname->len, MAX_MIDENT_LEN);
rtn_name.addr = trigname->addr;
if (!reg->open)
gv_init_reg(reg, NULL); /* Open the region before obtaining "csa" */
regcsa = &FILE_INFO(reg)->s_addrs;
assert('#' == rtn_name.addr[rtn_name.len - 1]);
for ( ; rttabent <= rtn_names_end; rttabent++)
{
if ((rttabent->rt_name.len < rtn_name.len) || memcmp(rttabent->rt_name.addr, rtn_name.addr, rtn_name.len))
{ /* Past the list of routines with same name as trigger but different runtime disambiguators */
rtn_vector = NULL;
break;
}
rtn_vector = rttabent->rt_adr;
trigdsc = (gv_trigger_t *)rtn_vector->trigr_handle;
gvt_trigger = trigdsc->gvt_trigger;
gvt = gvt_trigger->gv_target;
/* Target region and trigger routine's region do not match, continue */
if (gvt->gd_csa != regcsa)
continue;
/* Check if global name associated with the trigger is indeed mapped to the corresponding region
* by the gld. If not treat this case as if the trigger is invisible and move on
*/
gbl.addr = gvt->gvname.var_name.addr;
gbl.len = gvt->gvname.var_name.len;
TP_CHANGE_REG_IF_NEEDED(gvt->gd_csa->region);
csa = cs_addrs;
csd = csa->hdr;
COMPUTE_HASH_MNAME(&gvt->gvname);
GV_BIND_NAME_ONLY(gd_header, &gvt->gvname, gvnh_reg); /* does tp_set_sgm() */
if (((NULL == gvnh_reg->gvspan) && (gv_cur_region != reg))
|| ((NULL != gvnh_reg->gvspan) && !gvnh_spanreg_ismapped(gvnh_reg, gd_header, reg)))
continue;
/* Target region and trigger routine's region match, break (this check is a formality) */
if (gvt->gd_csa == regcsa)
break;
}
}
csa = NULL;
if (NULL == rtn_vector)
{ /* If runtime disambiguator was specified and routine is not found, look no further.
* Otherwise, look for it in the #t global of any (or specified) region in current gbldir.
*/
if (0 < origlen)
trigname->len = origlen; /* Restore length to include region disambiguator */
DBGTRIGR((stderr, "trigger_locate_andor_load: find trigger by name without disambiguator\n"));
if (runtime_disambiguator_specified
|| (TRIG_FAILURE_RC == trigger_source_read_andor_verify(trigname, &rtn_vector)))
{
RESTORE_REGION_INFO(save_currkey, save_gv_target, save_gv_cur_region, save_sgm_info_ptr, save_jnlpool);
ISSUE_TRIGNAMENF_ERROR_IF_APPROPRIATE(trigname);
return TRIG_FAILURE_RC;
}
trigdsc = (gv_trigger_t *)rtn_vector->trigr_handle;
assert(NULL != rtn_vector);
} else
{ /* Have a routine header addr. From that we can get the gv_trigger_t descriptor and from that, the
* gvt_trigger and other necessities.
*/
DBGTRIGR((stderr, "trigger_locate_andor_load: routine header found\n"));
trigdsc = (gv_trigger_t *)rtn_vector->trigr_handle;
gvt_trigger = trigdsc->gvt_trigger; /* We now know our base block now */
gvt = gv_target = gvt_trigger->gv_target; /* gv_target contains global name */
gbl.addr = gvt->gvname.var_name.addr;
gbl.len = gvt->gvname.var_name.len;
TP_CHANGE_REG_IF_NEEDED(gvt->gd_csa->region);
csa = cs_addrs;
csd = csa->hdr;
if (runtime_disambiguator_specified && (NULL != reg))
{ /* Runtime-disambiguator has been specified and routine was found. But region-name-disambiguator
* has also been specified. Check if found routine is indeed in the specified region. If not
* treat it as a failure to find the trigger.
*/
if (!reg->open)
gv_init_reg(reg, NULL);
if (&FILE_INFO(reg)->s_addrs != csa)
{
RESTORE_REGION_INFO(save_currkey, save_gv_target, save_gv_cur_region, save_sgm_info_ptr,
save_jnlpool);
ISSUE_TRIGNAMENF_ERROR_IF_APPROPRIATE(trigname);
return TRIG_FAILURE_RC;
}
/* Check if global name is indeed mapped to this region by the gld. If not treat this case as
* if the trigger is invisible and issue an error
*/
COMPUTE_HASH_MNAME(&gvt->gvname);
GV_BIND_NAME_ONLY(gd_header, &gvt->gvname, gvnh_reg); /* does tp_set_sgm() */
if (((NULL == gvnh_reg->gvspan) && (gv_cur_region != reg))
|| ((NULL != gvnh_reg->gvspan) && !gvnh_spanreg_ismapped(gvnh_reg, gd_header, reg)))
{
RESTORE_REGION_INFO(save_currkey, save_gv_target, save_gv_cur_region, save_sgm_info_ptr,
save_jnlpool);
ISSUE_TRIGNAMENF_ERROR_IF_APPROPRIATE(trigname);
return TRIG_FAILURE_RC;
}
}
assert(csd == cs_data);
}
DBGTRIGR((stderr, "trigger_locate_andor_load: leaving with source from rtnhdr 0x%lx\n",
(*rtn_vec) ? (*((rhdtyp **)rtn_vec))->trigr_handle : NULL));
RESTORE_REGION_INFO(save_currkey, save_gv_target, save_gv_cur_region, save_sgm_info_ptr, save_jnlpool);
assert(NULL != rtn_vector);
assert(trigdsc == rtn_vector->trigr_handle);
*rtn_vec = rtn_vector;
return 0;
}
#endif /* GTM_TRIGGER */
|