File: error_return.c

package info (click to toggle)
fis-gtm 7.1-006-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 32,908 kB
  • sloc: ansic: 344,906; asm: 5,184; csh: 4,859; sh: 2,000; awk: 294; makefile: 73; sed: 13
file content (134 lines) | stat: -rw-r--r-- 5,656 bytes parent folder | download | duplicates (7)
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
/****************************************************************
 *								*
 *	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) */
}