fis-gtm/sr_unix/error_return.c

135 lines
5.5 KiB
C

/****************************************************************
* *
* Copyright 2010, 2011 Fidelity Information Services, Inc *
* *
* 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"
#include "gtm_stdlib.h"
#include "gtm_stdio.h"
#include "error.h"
#include "error_trap.h"
#include "dollar_zlevel.h"
#include <rtnhdr.h>
#include "stack_frame.h"
#include "golevel.h"
#include "io.h"
#include "send_msg.h"
#define BASE_FRAME(fp) ((fp->type & SFT_DM) || (fp->flags & SFF_CI))
GBLREF stack_frame *frame_pointer;
GBLREF unsigned short proc_act_type;
GBLREF dollar_ecode_type dollar_ecode; /* structure containing $ECODE related information */
GBLREF int mumps_status;
GBLREF stack_frame *error_frame;
GBLREF io_desc *gtm_err_dev;
GBLREF mval dollar_zstatus;
error_def(ERR_JIUNHNDINT);
error_def(ERR_REPEATERROR);
void error_return(void)
{
int parent_level, unwcnt;
stack_frame *curframe, *cur_counted_frame, *parent_counted_frame;
boolean_t rethrow_needed = FALSE, dev_act_err, transcendental, zintrframe;
DBGEHND((stderr, "error_return: Entered\n"));
assert((frame_pointer->flags & SFF_ETRAP_ERR) || (error_frame == frame_pointer));
unwcnt = 0;
/* Determine counted frame at the current $zlevel */
for (curframe = frame_pointer;
(NULL != curframe) && !(curframe->type & SFT_COUNT) && !BASE_FRAME(curframe);
curframe = curframe->old_frame_pointer)
unwcnt++; /* (don't need to worry about trigger frames here as they are counted and stop the loop) */
DBGEHND((stderr, "error_return: cur_counted_frame found with unwind count %d\n", unwcnt));
cur_counted_frame = curframe;
NULLIFY_ERROR_FRAME; /* reset error_frame */
dev_act_err = ((NULL != cur_counted_frame) && (cur_counted_frame->flags & SFF_ETRAP_ERR)
&& (cur_counted_frame->flags & SFF_DEV_ACT_ERR));
zintrframe = (SFT_ZINTR & curframe->type);
if (dev_act_err || (0 != dollar_ecode.index))
rethrow_needed = TRUE;
/* If the top level error is a device exception error, we do not want to unwind upto the parent frame but instead
* rethrow the error at the current level and use $ztrap/$etrap exception handling. In case even that fails,
* we will come again to error_return at which point, we unwind to the parent frame.
*/
if (!dev_act_err && NULL != curframe)
{ /* We need to unwind this frame to either rethrow error or MUM_TSTART. If this lands us on a trigger frame,
* whether that is ok or not depends on whether we will end up rethrowing the error or doing a MUM_TSTART. If we
* are rethrowing the error, we must not land on a trigger frame but must unroll it too. In the MUM_TSTART case,
* we are resuming at that point via a simulated QUIT so this is ok.
*/
do
{
curframe = curframe->old_frame_pointer;
unwcnt++;
# ifdef GTM_TRIGGER
if (rethrow_needed && (SFT_TRIGR & curframe->type))
{ /* With a rethrow, we cannot use a trigger base-frame - back up one frame prior to the frame */
curframe = *(stack_frame **)(curframe + 1);
unwcnt++;
}
# endif
transcendental = ((SFT_ZTRAP & curframe->type) || (SFT_DEV_ACT & curframe->type));
} while (transcendental && (NULL != curframe));
}
/* Check a couple of conditions that could turn off rethrow_needed:
*
* 1. If we ended up on a callin frame which needs to just return to the C caller (error handling abandonded but the error
* code is returned to the caller).
* 2. If we ended up on a direct mode frame - errors just get printed here.
* 3. If we are unwinding a ZINTERRUPT frame (error handling abandoned - send message to operator log).
*/
if (rethrow_needed && BASE_FRAME(curframe))
{ /* If the computed frame is a base frame for call-ins, we cannot do rethrow and must use MUM_TSTART to return to
* the call-in invocation code (gtm_ci()).
*/
rethrow_needed = FALSE;
DBGEHND((stderr, "error_return: rethrow_needed set to FALSE due to call-in base frame"));
}
if (rethrow_needed && zintrframe)
{ /* If we are unwinding a ZINTERRUPT frame, error processing stops here but send a message to the operator log
* to notify users of the un-handled error.
*/
rethrow_needed = FALSE;
DBGEHND((stderr, "error_return: rethrow_needed set to FALSE due to unwinding errant zinterrupt frame"));
send_msg(VARLSTCNT(3) ERR_JIUNHNDINT, 2, dollar_zstatus.str.len, dollar_zstatus.str.addr);
}
parent_counted_frame = curframe; /* Not parent frame for device errors -- still at error counted frame */
/* Exit if we are at the bottom of the stack */
parent_level = dollar_zlevel() - 1;
if ((NULL == parent_counted_frame) || (1 > parent_level))
{
EXIT(dollar_ecode.error_last_ecode);
}
assert(0 < parent_level);
DBGEHND((stderr, "error_return: unwcnt: %d rethrow_needed: %d dev_act_err: %d\n", unwcnt, rethrow_needed, dev_act_err));
GOFRAMES(unwcnt, FALSE, FALSE);
assert(parent_counted_frame == frame_pointer);
assert(!proc_act_type);
if (rethrow_needed)
{
rts_error(VARLSTCNT(1) ERR_REPEATERROR);
assert(FALSE); /* the previous rts_error() should not return */
}
/* zero the error device just to be safe */
assert(NULL == gtm_err_dev);
gtm_err_dev = NULL;
if (!zintrframe)
{
if (parent_counted_frame->flags & SFF_CI) /* Unhandled error in call-in: return to gtm_ci */
mumps_status = dollar_ecode.error_last_ecode;
MUM_TSTART;
}
return; /* Continue in caller (likely getframe macro) */
}