void release_private_code_copy(rhdtyp *rtn)
{
#	ifdef USHBIN_SUPPORTED
	assert(NULL != rtn->shared_ptext_adr);
	assert(rtn->shared_ptext_adr != rtn->ptext_adr);
	DBGARLNK((stderr, "release_private_code_copy: Releasing private code copy at 0x"lvaddr" for rtnhdr 0x"lvaddr"\n",
		  rtn->ptext_adr, rtn));
	adjust_frames(rtn->ptext_adr, rtn->ptext_end_adr, rtn->shared_ptext_adr);
	GTM_TEXT_FREE(rtn->ptext_adr);
	do
	{	/* Since more than one version of a module may exist at a given time, run the routine
		 * header chain and check all versions - releasing the private copy if it exists.
		 */
		DBGARLNK((stderr, "release_private_code_copy: rtnhdr 0x"lvaddr"  Previous values - ptext_adr: 0x"lvaddr
			  "  ptext_end_adr: 0x"lvaddr"\n", rtn, rtn->ptext_adr, rtn->ptext_end_adr));
		rtn->ptext_end_adr = rtn->shared_ptext_adr + (rtn->ptext_end_adr - rtn->ptext_adr);
		rtn->ptext_adr = rtn->shared_ptext_adr;
		DBGARLNK((stderr, "release_private_code_copy: rtnhdr 0x"lvaddr"  New values      - ptext_adr: 0x"lvaddr
			  "  ptext_end_adr: 0x"lvaddr"\n", rtn, rtn->ptext_adr, rtn->ptext_end_adr));
		/* Check for special case loop terminator. If this was a routine copy created when a routine in use was
		 * recursively relinked, we do not want to follow its backchain and change those modules because this
		 * routine copy is not part of that chain. The backpointer is only to find the original routine header
		 * when this routine terminates. So if this routine is a recursive copy, stop the loop now.
		 */
		rtn = ((NULL != rtn->old_rhead_adr) && (rtn != rtn->old_rhead_adr->active_rhead_adr))
			? (rhdtyp *)rtn->old_rhead_adr : NULL;
	} while (NULL != rtn);
	DBGARLNK((stderr, "release_private_code_copy: Complete\n"));
#	endif
	return;
}
void release_private_code_copy(rhdtyp *rtn)
{
#ifdef USHBIN_SUPPORTED
		assert(NULL != rtn->shlib_handle);
		assert(NULL != rtn->shared_ptext_adr);

		adjust_frames(rtn->ptext_adr, rtn->ptext_end_adr, rtn->shared_ptext_adr);
		GTM_TEXT_FREE(rtn->ptext_adr);
		rtn->ptext_end_adr = rtn->shared_ptext_adr + (rtn->ptext_end_adr - rtn->ptext_adr);
		rtn->ptext_adr = rtn->shared_ptext_adr;
		rtn->shared_ptext_adr = NULL;
#endif
	return;
}
void release_private_code_copy(rhdtyp *rtn)
{
#	ifdef USHBIN_SUPPORTED
	assert(NULL != rtn->shared_ptext_adr);
	assert(rtn->shared_ptext_adr != rtn->ptext_adr);

	adjust_frames(rtn->ptext_adr, rtn->ptext_end_adr, rtn->shared_ptext_adr);
	GTM_TEXT_FREE(rtn->ptext_adr);
	do
	{	/* Since more than one version of a module may exist at a given time, run the routine
		 * header chain and check all versions - releasing the private copy if it exists.
		 */
		rtn->ptext_end_adr = rtn->shared_ptext_adr + (rtn->ptext_end_adr - rtn->ptext_adr);
		rtn->ptext_adr = rtn->shared_ptext_adr;
		rtn = (rhdtyp *)rtn->old_rhead_adr;
	} while (NULL != rtn);
#	endif
	return;
}
示例#4
0
/* Routine to eliminate the zlinked trigger code for a given trigger about to be deleted. Operations performed
 * differ depending on platform type (shared binary or not).
 */
void gtm_trigger_cleanup(gv_trigger_t *trigdsc)
{
	rtn_tabent	*rbot, *mid, *rtop;
	mident		*rtnname;
	rhdtyp		*rtnhdr;
	textElem	*telem;
	int		comp, size;
	stack_frame	*fp, *fpprev;
	mname_entry	key;
	ht_ent_mname    *tabent;
	routine_source	*src_tbl;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	/* First thing to do is release trigger source field if it exists */
	if (0 < trigdsc->xecute_str.str.len)
	{
		free(trigdsc->xecute_str.str.addr);
		trigdsc->xecute_str.str.len = 0;
		trigdsc->xecute_str.str.addr = NULL;
	}
	/* Next thing to do is find the routine header in the rtn_names list so we can remove it. */
	rtnname = &trigdsc->rtn_desc.rt_name;
	rtnhdr = trigdsc->rtn_desc.rt_adr;
	rbot = rtn_names;
	rtop = rtn_names_end;
	for (;;)
	{	/* See if routine exists in list via a binary search which reverts to serial
		   search when # of items drops below the threshold S_CUTOFF.
		*/
		if ((rtop - rbot) < S_CUTOFF)
		{
			comp = -1;
			for (mid = rbot; mid <= rtop ; mid++)
			{
				MIDENT_CMP(&mid->rt_name, rtnname, comp);
				if (0 == comp)
					break;
				if (0 < comp)
					GTMASSERT;	/* Routine should be found */
			}
			break;
		} else
		{	mid = rbot + (rtop - rbot)/2;
			MIDENT_CMP(&mid->rt_name, rtnname, comp);
			if (0 == comp)
				break;
			else if (0 > comp)
			{
				rbot = mid + 1;
				continue;
			} else
			{
				rtop = mid - 1;
				continue;
			}
		}
	}
#	ifdef DEBUG
	assert(rtnhdr == mid->rt_adr);
	/* Verify trigger routine we want to remove is not currently active. If it is, we need to GTMASSERT.
	 * Triggers are not like regular routines since they should only ever be referenced from the stack during a
	 * transaction. Likewise, we should only ever load the triggers as the first action in that transaction.
	 */
	for (fp = frame_pointer; fp ; fp = fpprev)
	{
		fpprev = fp->old_frame_pointer;
#		ifdef GTM_TRIGGER
		if (NULL != fpprev && SFT_TRIGR & fpprev->type)
			fpprev = *(stack_frame **)(fpprev + 1);
#		endif
		/* Only one possible version of a trigger routine */
		assert(USHBIN_ONLY(NULL) NON_USHBIN_ONLY(fp->rvector) == OLD_RHEAD_ADR(CURRENT_RHEAD_ADR(fp->rvector)));
		assert(fp->rvector != rtnhdr);
	}
#	endif
	/* Remove break points in this routine before rmv from rtntbl */
	zr_remove(rtnhdr, BREAKMSG);
	/* Release any $TEXT() info this trigger has loaded */
	if (NULL != (TREF(rt_name_tbl)).base)
	{
		key.var_name = mid->rt_name;
		COMPUTE_HASH_MNAME(&key);
		if (NULL != (tabent = lookup_hashtab_mname(TADR(rt_name_tbl), &key)))	/* note assignment */
		{	/* We have a hash entry. Whether it has a value or not, it has a key name (if this is
			 * the first time this trigger is being deleted) that may be pointing into the routine we
			 * are about to remove. Migrate this key name to the stringpool.
			 */
			s2pool(&tabent->key.var_name);
			if (NULL != tabent->value)
			{	/* Has value, release the source. Entries and source are malloc'd in two blocks on UNIX */
				src_tbl = (routine_source *)tabent->value;
				if (NULL != src_tbl->srcbuff)
					free(src_tbl->srcbuff);
				free(src_tbl);
				tabent->value = NULL;
			}
		}
	}
	/* Remove the routine from the rtn_table */
	size = INTCAST((char *)rtn_names_end - (char *)mid);
	if (0 < size)
		memmove((char *)mid, (char *)(mid + 1), size);	/* Remove this routine name from sorted table */
	rtn_names_end--;
	urx_remove(rtnhdr);					/* Remove any unresolved entries */
#	ifdef USHBIN_SUPPORTED
	stp_move((char *)rtnhdr->literal_text_adr,
		 (char *)(rtnhdr->literal_text_adr + rtnhdr->literal_text_len));
	GTM_TEXT_FREE(rtnhdr->ptext_adr);			/* R/O releasable section */
	free(rtnhdr->literal_adr);				/* R/W releasable section part 1 */
	free(rtnhdr->linkage_adr);				/* R/W releasable section part 2 */
	free(rtnhdr->labtab_adr);				/* Usually non-releasable but triggers don't have labels so
								 * this is just cleaning up a dangling null malloc
								 */
	free(rtnhdr);
#	else
#		if (!defined(__linux__) && !defined(__CYGWIN__)) || !defined(__i386) || !defined(COMP_GTA)
#			error Unsupported NON-USHBIN platform
#		endif
	/* For a non-shared binary platform we need to get an approximate addr range for stp_move. This is not
	 * done when a routine is replaced on these platforms but in this case we are able to due to the isolated
	 * environment if we only take the precautions of migrating potential literal text which may have been
	 * pointed to by any set environment variables.
	 * In this format, the only platform we support currently is Linux-x86 (i386) which uses GTM_TEXT_ALLOC
	 * to allocate special storage for it to put executable code in. We can access the storage header for
	 * this storage and find out how big it is and use that information to give stp_move a good range since
	 * the literal segment occurs right at the end of allocated storage (for which there is no pointer
	 * in the fileheader).
	 */
	telem = (textElem *)((char *)rtnhdr - offsetof(textElem, userStorage));
	assert(TextAllocated == telem->state);
	stp_move((char *)LNRTAB_ADR(rtnhdr) + (rtnhdr->lnrtab_len * SIZEOF(lnr_tabent)),
		 (char *)rtnhdr + telem->realLen);
	GTM_TEXT_FREE(rtnhdr);
#	endif
}