546 lines
15 KiB
Text
546 lines
15 KiB
Text
head 2.2;
|
|
access;
|
|
symbols
|
|
V4_1_1_1:2.2
|
|
Rel_2_1:2.1;
|
|
locks; strict;
|
|
comment @ @;
|
|
|
|
|
|
2.2
|
|
date 2001.01.25.14.07.42; author cibrario; state Exp;
|
|
branches;
|
|
next 2.1;
|
|
|
|
2.1
|
|
date 2000.05.26.14.31.28; author cibrario; state Rel;
|
|
branches;
|
|
next 1.6;
|
|
|
|
1.6
|
|
date 97.01.15.13.34.45; author cibrario; state Exp;
|
|
branches;
|
|
next 1.1;
|
|
|
|
1.1
|
|
date 96.05.28.12.55.51; author cibrario; state Beta;
|
|
branches;
|
|
next ;
|
|
|
|
|
|
desc
|
|
@This module implements the condition signalling function of CHF
|
|
@
|
|
|
|
|
|
2.2
|
|
log
|
|
@Added partial Win32 support (Windows CE only).
|
|
@
|
|
text
|
|
@/* .+
|
|
|
|
.identifier : $Id: chf_sig.c,v 2.1 2000/05/26 14:31:28 cibrario Rel cibrario $
|
|
.context : CHF, Condition Handling Facility
|
|
.title : $RCSfile: chf_sig.c,v $, condition generation
|
|
.kind : C source
|
|
.author : Ivan Cibrario B.
|
|
.site : CSTV-CNR
|
|
.creation : 3-May-1996
|
|
.keywords : *
|
|
.description :
|
|
This module implements the condition signalling function of CHF
|
|
|
|
.include : Chf.h
|
|
|
|
.notes :
|
|
$Log: chf_sig.c,v $
|
|
Revision 2.1 2000/05/26 14:31:28 cibrario
|
|
- Fixed spelling of CHF_SIGNALLING -> CHF_SIGNALING
|
|
- Replaced longjmp() with siglongjmp()
|
|
- New ChfAction code CHF_UNWIND_KEEP: ChfSignal() unwinds the
|
|
execution stack, but keeps the topmost condition group on the
|
|
condition stack
|
|
|
|
Revision 1.6 1997/01/15 13:34:45 cibrario
|
|
Fixed a wrong adjustment of the condition handler stack pointer after
|
|
an unwind operation.
|
|
Updated the condition handler calls in order to pass to the handlers the
|
|
private handler context pointer.
|
|
|
|
Revision 1.1 1996/05/28 12:55:51 cibrario
|
|
Initial revision
|
|
|
|
|
|
.- */
|
|
|
|
#ifndef lint
|
|
static char rcs_id[] = "$Id: chf_sig.c,v 2.1 2000/05/26 14:31:28 cibrario Rel cibrario $";
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#ifndef _WIN32
|
|
#include <errno.h>
|
|
#endif
|
|
#include <setjmp.h>
|
|
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#include <tchar.h>
|
|
#endif
|
|
|
|
#include "Chf.h"
|
|
#include "ChfPriv.h"
|
|
|
|
|
|
/* .+
|
|
|
|
.title : ChfSignal
|
|
.kind : C function
|
|
.creation : 10-May-1996
|
|
.description :
|
|
This function signals the topmost condition group currently in the
|
|
condition stack, and performs the actions requested by the condition
|
|
handlers.
|
|
|
|
NOTE: This function uses the CHF function 'ChfAbort()' to
|
|
abort the application if either
|
|
- CHF has not been initialized correctly (abort code CHF_ABORT_INIT)
|
|
- the last handler on the handler stack has returned an invalid action
|
|
code (abort code CHF_ABORT_INVALID_ACTION)
|
|
- one of the handlers has requested the CHF_UNWIND action while
|
|
CHF was already unwinding (abort code CHF_ABORT_ALREADY_UNWINDING)
|
|
- a CHF_FATAL condition was signalled while CHF was unwinding
|
|
(abort code CHF_ABORT_FATAL_UNWINDING)
|
|
- all the handlers refused to handle a condition (abort code
|
|
CHF_ABORT_IMPROPERLY_HANDLED)
|
|
|
|
.call :
|
|
ChfSignal();
|
|
.input :
|
|
void
|
|
.output :
|
|
void
|
|
.status_codes :
|
|
(*) CHF_F_COND_STACK_FULL, the condition stack is full
|
|
(*) CHF_F_INVALID_ACTION, invalid handler action (%d)
|
|
.notes :
|
|
1.1, 10-May-1996, creation
|
|
1.6, 15-Jan-1997, update & bug fix:
|
|
- fixed a wrong adjustment of the condition handler stack pointer after
|
|
an unwind operation.
|
|
- updated the condition handler calls in order to pass to the handlers the
|
|
private handler context pointer, too.
|
|
2.1, 19-May-2000, update:
|
|
- added support for structured condition handling
|
|
|
|
.- */
|
|
void ChfSignal(
|
|
void
|
|
)
|
|
{
|
|
ChfState saved_state;
|
|
ChfDescriptor *saved_condition_base;
|
|
ChfDescriptor *current_condition;
|
|
ChfHandlerDescriptor *saved_handler_sp;
|
|
ChfHandlerDescriptor *handler_up;
|
|
ChfHandlerDescriptor *unwind_handler;
|
|
ChfAction handler_result;
|
|
|
|
/* Check that CHF has been correctly initialized and save the current CHF
|
|
state. If CHF was CHF_IDLE change state to CHF_SIGNALING, else if CHF was
|
|
CHF_UNWINDING change to CHF_SIGNAL_UNWINDING, otherwise remain in the
|
|
previous state (that must be CHF_SIGNALING)
|
|
*/
|
|
if(chf_context.state == CHF_UNKNOWN) ChfAbort(CHF_ABORT_INIT);
|
|
saved_state = chf_context.state;
|
|
|
|
if(chf_context.state == CHF_IDLE)
|
|
chf_context.state = CHF_SIGNALING;
|
|
else if(chf_context.state == CHF_UNWINDING)
|
|
chf_context.state = CHF_SIGNAL_UNWINDING;
|
|
|
|
if(chf_context.condition_sp > chf_context.condition_base)
|
|
{
|
|
/* Save the base of the current condition group and then update it in
|
|
order to allow further generation of conditions inside the condition
|
|
handlers that will be called soon.
|
|
*/
|
|
current_condition = chf_context.condition_sp-1;
|
|
saved_condition_base = chf_context.condition_base;
|
|
chf_context.condition_base = chf_context.condition_sp;
|
|
|
|
/* Save the current condition handler pointer */
|
|
saved_handler_sp = chf_context.handler_sp;
|
|
|
|
/* Call the condition handlers; the loop will exit either:
|
|
- when the handler stack is empty, or
|
|
- when the current handler returns either CHF_CONTINUE or CHF_UNWIND
|
|
*/
|
|
handler_result = CHF_RESIGNAL;
|
|
while(handler_result == CHF_RESIGNAL &&
|
|
chf_context.handler_sp > chf_context.handler_stack)
|
|
{
|
|
chf_context.handler_sp--;
|
|
|
|
/* The current condition handler, described by chf_context.handler_sp,
|
|
can recursively invoke ChfGenerate() and ChfSignal().
|
|
|
|
ChfGenerate() will store the new condition group starting from
|
|
chf_context.condition_sp, that points to the first free slot
|
|
of the condition stack. During the first generation, since
|
|
chf_context.condition_sp == chf_context.condition_base, the
|
|
link pointer of the condition will be NULL and, therefore,
|
|
the condition will be the first of a new condition group.
|
|
|
|
ChfSignal() will signal the condition group described by the
|
|
stack block from chf_context.condition_base to
|
|
chf_context.condition_sp-1, if it contains at least one condition;
|
|
it will call the handlers starting from chf_context.handler_sp-1,
|
|
that describes the handler immediately preceding the current handler.
|
|
*/
|
|
handler_result = chf_context.handler_sp->handler(
|
|
current_condition, chf_context.state,
|
|
chf_context.handler_sp->handler_context);
|
|
|
|
/* When the CHF state is CHF_SIGNALING, any condition group generated
|
|
but not yet signalled when the current handler exits must be merged
|
|
with the condition group currently being signalled, in order to allow
|
|
the condition handlers to add their own conditions to the condition
|
|
group. If the severity of the previous condition group was CHF_FATAL,
|
|
the severity of the new group is forced to CHF_FATAL, too.
|
|
|
|
When the CHF state is CHF_UNWINDING, the condition group for
|
|
which the UNWIND has been requested is 'frozen', no further
|
|
modifications are allowed on it, and the condition group is simply
|
|
discarded.
|
|
*/
|
|
if(chf_context.condition_sp > chf_context.condition_base)
|
|
{
|
|
if(chf_context.state == CHF_SIGNALING)
|
|
{
|
|
/* Force the new severity to CHF_FATAL if necessary */
|
|
if(ChfGetSeverity(current_condition) == CHF_FATAL)
|
|
ChfGetSeverity(chf_context.condition_sp-1) = CHF_FATAL;
|
|
|
|
/* Link together the condition groups */
|
|
chf_context.condition_base->next = current_condition;
|
|
current_condition = chf_context.condition_sp-1;
|
|
chf_context.condition_base = chf_context.condition_sp;
|
|
}
|
|
|
|
else
|
|
chf_context.condition_sp = chf_context.condition_base;
|
|
}
|
|
|
|
/* The action CHF_CONTINUE is not allowed if the current condition
|
|
severity is CHF_FATAL; it's automatically changed to CHF_RESIGNAL
|
|
*/
|
|
if(handler_result == CHF_CONTINUE &&
|
|
ChfGetSeverity(current_condition) == CHF_FATAL)
|
|
handler_result = CHF_RESIGNAL;
|
|
}
|
|
|
|
/* Perform the action requested by the last condition handler invoked */
|
|
switch(handler_result)
|
|
{
|
|
case CHF_CONTINUE:
|
|
{
|
|
/* Restore the handler stack pointer; the next ChfSignal() invoked
|
|
from our same nesting level will invoke our same handler chain
|
|
again.
|
|
*/
|
|
chf_context.handler_sp = saved_handler_sp;
|
|
|
|
/* Discard the current condition group */
|
|
chf_context.condition_base = chf_context.condition_sp =
|
|
saved_condition_base;
|
|
|
|
/* Restore che saved CHF state */
|
|
chf_context.state = saved_state;
|
|
|
|
/* Continue from the instruction following the ChfSignal() */
|
|
break;
|
|
}
|
|
|
|
case CHF_UNWIND:
|
|
case CHF_UNWIND_KEEP:
|
|
{
|
|
/* Unwind the execution stack. Check that another unwind isn't
|
|
already in progress
|
|
*/
|
|
if(chf_context.state == CHF_UNWINDING)
|
|
ChfAbort(CHF_ABORT_ALREADY_UNWINDING);
|
|
|
|
else
|
|
{
|
|
/* Change CHF state */
|
|
chf_context.state = CHF_UNWINDING;
|
|
|
|
/* chf_context.handler_sp points to the condition handler that
|
|
has requested the unwind; call all the handlers again, starting
|
|
from saved_handler_sp (top of the handler stack) up to and
|
|
including chf_context.handler_sp.
|
|
*/
|
|
handler_up = saved_handler_sp;
|
|
|
|
while(handler_up > chf_context.handler_sp)
|
|
{
|
|
ChfAction unw_handler_result;
|
|
handler_up--;
|
|
|
|
/* The current condition handler, described by handler_up
|
|
can recursively invoke ChfGenerate() and ChfSignal().
|
|
|
|
ChfGenerate() will store the new condition group starting from
|
|
chf_context.condition_sp, that points to the first free slot
|
|
of the condition stack. During the first generation, since
|
|
chf_context.condition_sp == chf_context.condition_base, the
|
|
link pointer of the condition will be NULL and, therefore,
|
|
the condition will be the first of a new condition group.
|
|
|
|
ChfSignal() will generate the condition group described by the
|
|
stack block from chf_context.condition_base to
|
|
chf_context.condition_sp-1, if it contains at least one
|
|
condition; it will call the handlers starting from
|
|
chf_context.handler_sp-1, that describes the handler
|
|
immediately preceding the handler that has requested the unwind.
|
|
|
|
Further unwind requests are not allowed, and will trigger
|
|
the condition CHF_F_UNWINDING
|
|
*/
|
|
unw_handler_result = handler_up->handler(
|
|
current_condition, chf_context.state,
|
|
handler_up->handler_context);
|
|
|
|
/* When the CHF state is CHF_UNWINDING, any condition group
|
|
generated but not yet signalled when the current handler
|
|
returns must be discarded
|
|
*/
|
|
chf_context.condition_sp = chf_context.condition_base;
|
|
}
|
|
|
|
/* Restore the handler stack pointer, discarding the unwinded
|
|
condition handlers. chf_context.handler_sp points to the
|
|
handler that requested the unwind; that handler has been
|
|
unwinded and its location is now the first free slot in the
|
|
condition handler stack.
|
|
*/
|
|
unwind_handler = chf_context.handler_sp;
|
|
|
|
if(handler_result == CHF_UNWIND)
|
|
{
|
|
/* Normal unwind:
|
|
restore the condition stack pointers, discarding all condition
|
|
groups.
|
|
*/
|
|
chf_context.condition_base = chf_context.condition_sp =
|
|
chf_context.condition_stack;
|
|
}
|
|
else
|
|
{
|
|
/* Special unwind for structured condition handling:
|
|
restore the condition_base pointer only, to keep the
|
|
topmost condition group on the condition stack. This way,
|
|
the condition group remains accessible after the unwind.
|
|
*/
|
|
chf_context.condition_base = saved_condition_base;
|
|
}
|
|
|
|
/* Change the CHF state to CHF_IDLE, and execute longjmp().
|
|
If the handler hasn't a valid unwind_context associated with it,
|
|
simply abort the application.
|
|
*/
|
|
chf_context.state = CHF_IDLE;
|
|
|
|
if(unwind_handler->unwind_context == CHF_NULL_CONTEXT)
|
|
ChfAbort(CHF_ABORT_SILENT);
|
|
else
|
|
ChfSiglongjmp(unwind_handler->unwind_context, 1);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case CHF_RESIGNAL:
|
|
{
|
|
ChfAbort(
|
|
(chf_context.state == CHF_SIGNALING) ?
|
|
CHF_ABORT_IMPROPERLY_HANDLED : CHF_ABORT_FATAL_UNWINDING);
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
/* Invalid handler action detected; generate and immediately signal a
|
|
condition if the broken handler isn't the last handler on the stack,
|
|
otherwise call ChfAbort()
|
|
*/
|
|
if(chf_context.handler_sp > chf_context.handler_stack)
|
|
{
|
|
ChfCondition CHF_F_INVALID_ACTION, CHF_FATAL, handler_result
|
|
ChfEnd;
|
|
|
|
ChfSignal();
|
|
}
|
|
|
|
else
|
|
ChfAbort(CHF_ABORT_INVALID_ACTION);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Restore the old CHF state */
|
|
chf_context.state = saved_state;
|
|
}
|
|
|
|
|
|
/* .+
|
|
|
|
.title : ChfDiscard
|
|
.kind : C function
|
|
.creation : 17-May-1996
|
|
.description :
|
|
This function discards the topmost condition group currently in the
|
|
condition stack, without signalling it. The function does nothing if
|
|
the condition stack is empty.
|
|
|
|
NOTE: This function uses the CHF function 'ChfAbort()' to
|
|
abort the application if either
|
|
- CHF has not been initialized correctly (abort code CHF_ABORT_INIT)
|
|
|
|
.call :
|
|
ChfDiscard();
|
|
.input :
|
|
void
|
|
.output :
|
|
void
|
|
.status_codes :
|
|
none
|
|
.notes :
|
|
1.1, 17-May-1996, creation
|
|
|
|
.- */
|
|
void ChfDiscard( /* Discard the current conditions */
|
|
void
|
|
)
|
|
{
|
|
/* Check that CHF has been correctly initialized */
|
|
if(chf_context.state == CHF_UNKNOWN) ChfAbort(CHF_ABORT_INIT);
|
|
|
|
/* Reset the current condition stack pointer to the current condition
|
|
stack base pointer
|
|
*/
|
|
chf_context.condition_sp = chf_context.condition_base;
|
|
}
|
|
@
|
|
|
|
|
|
2.1
|
|
log
|
|
@- Fixed spelling of CHF_SIGNALLING -> CHF_SIGNALING
|
|
- Replaced longjmp() with siglongjmp()
|
|
- New ChfAction code CHF_UNWIND_KEEP: ChfSignal() unwinds the
|
|
execution stack, but keeps the topmost condition group on the
|
|
condition stack
|
|
@
|
|
text
|
|
@d3 1
|
|
a3 1
|
|
.identifier : $Id: chf_sig.c,v 1.6 1997/01/15 13:34:45 cibrario Exp cibrario $
|
|
d18 7
|
|
d38 1
|
|
a38 1
|
|
static char rcs_id[] = "$Id: chf_sig.c,v 1.6 1997/01/15 13:34:45 cibrario Exp cibrario $";
|
|
d43 1
|
|
d45 1
|
|
d48 5
|
|
d320 1
|
|
a320 1
|
|
siglongjmp(unwind_handler->unwind_context, 1);
|
|
@
|
|
|
|
|
|
1.6
|
|
log
|
|
@Fixed a wrong adjustment of the condition handler stack pointer after
|
|
an unwind operation.
|
|
Updated the condition handler calls in order to pass to the handlers the
|
|
private handler context pointer.
|
|
@
|
|
text
|
|
@d3 1
|
|
a3 1
|
|
.identifier : $Id$
|
|
d5 1
|
|
a5 1
|
|
.title : $RCSfile$, condition generation
|
|
d17 7
|
|
a23 1
|
|
$Log$
|
|
d31 1
|
|
a31 1
|
|
static char rcs_id[] = "$Id$";
|
|
d81 2
|
|
d98 1
|
|
a98 1
|
|
state. If CHF was CHF_IDLE change state to CHF_SIGNALLING, else if CHF was
|
|
d100 1
|
|
a100 1
|
|
previous state (that must be CHF_SIGNALLING)
|
|
d106 1
|
|
a106 1
|
|
chf_context.state = CHF_SIGNALLING;
|
|
d153 1
|
|
a153 1
|
|
/* When the CHF state is CHF_SIGNALLING, any condition group generated
|
|
d167 1
|
|
a167 1
|
|
if(chf_context.state == CHF_SIGNALLING)
|
|
d214 1
|
|
d236 1
|
|
d259 1
|
|
a259 1
|
|
handler_result = handler_up->handler(
|
|
d278 18
|
|
a295 5
|
|
/* Restore the condition stack pointers, discarding all condition
|
|
groups.
|
|
*/
|
|
chf_context.condition_base = chf_context.condition_sp =
|
|
chf_context.condition_stack;
|
|
d306 1
|
|
a306 1
|
|
longjmp(*(unwind_handler->unwind_context), 1);
|
|
d315 1
|
|
a315 1
|
|
(chf_context.state == CHF_SIGNALLING) ?
|
|
@
|
|
|
|
|
|
1.1
|
|
log
|
|
@Initial revision
|
|
@
|
|
text
|
|
@d18 2
|
|
d21 1
|
|
d70 5
|
|
d142 2
|
|
a143 1
|
|
current_condition, chf_context.state);
|
|
d250 2
|
|
a251 1
|
|
current_condition, chf_context.state);
|
|
d262 3
|
|
a264 2
|
|
handler that requested the unwind and must be adjusted to
|
|
point to the handler that immediately precedes it.
|
|
d266 1
|
|
a266 1
|
|
unwind_handler = chf_context.handler_sp--;
|
|
@
|