diff options
Diffstat (limited to 'private/crt32/misc/winsig.c')
-rw-r--r-- | private/crt32/misc/winsig.c | 709 |
1 files changed, 709 insertions, 0 deletions
diff --git a/private/crt32/misc/winsig.c b/private/crt32/misc/winsig.c new file mode 100644 index 000000000..310f1c62f --- /dev/null +++ b/private/crt32/misc/winsig.c @@ -0,0 +1,709 @@ +/*** +*winsig.c - C signal support +* +* Copyright (c) 1991-1993, Microsoft Corporation. All rights reserved +* +*Purpose: +* Defines signal(), raise() and supporting functions. +* +*Revision History: +* 10-21-91 GJF Signal for Win32 and Dosx32. Copied from old signal.c +* (the Cruiser implementation with some revisions for +* Win32), then extensively rewritten. +* 11-08-91 GJF Cleaned up header files usage. +* 12-13-91 GJF Fixed multi-thread build. +* 09-30-92 SRW Add WINAPI keyword to CtrlC handler +* 02-17-93 GJF Changed for new _getptd(). +* +*******************************************************************************/ + +#ifndef _POSIX_ + +#include <cruntime.h> +#include <errno.h> +#include <float.h> +#include <malloc.h> +#include <os2dll.h> +#include <oscalls.h> +#include <signal.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +/* + * look up the first entry in the exception-action table corresponding to + * the given signal + */ +#ifdef MTHREAD +static struct _XCPT_ACTION * _CRTAPI3 siglookup(int, struct _XCPT_ACTION *); +#else /* not MTHREAD */ +static struct _XCPT_ACTION * _CRTAPI3 siglookup(int); +#endif /* MTHREAD */ + +/* + * variables holding action codes (and code pointers) for SIGINT, SIGBRK, + * SIGABRT and SIGTERM. + * + * note that the disposition (i.e., action to be taken upon receipt) of + * these signals is defined on a per-process basis (not per-thread)!! + */ + +static _PHNDLR ctrlc_action = SIG_DFL; /* SIGINT */ +static _PHNDLR ctrlbreak_action = SIG_DFL; /* SIGBREAK */ +static _PHNDLR abort_action = SIG_DFL; /* SIGABRT */ +static _PHNDLR term_action = SIG_DFL; /* SIGTERM */ + +/* + * flag indicated whether or not a handler has been installed to capture + * ^C and ^Break events. + */ +static int ConsoleCtrlHandler_Installed = 0; + + +/*** +*static BOOL WINAPI ctrlevent_capture(DWORD CtrlType) - capture ^C and ^Break events +* +*Purpose: +* Capture ^C and ^Break events from the console and dispose of them +* according the values in ctrlc_action and ctrlbreak_action, resp. +* This is the routine that evokes the user-defined action for SIGINT +* (^C) or SIGBREAK (^Break) installed by a call to signal(). +* +*Entry: +* DWORD CtrlType - indicates type of event, two values: +* CTRL_C_EVENT +* CTRL_BREAK_EVENT +* +*Exit: +* Returns TRUE to indicate the event (signal) has been handled. +* Otherwise, returns FALSE. +* +*Exceptions: +* +*******************************************************************************/ + +static BOOL WINAPI ctrlevent_capture ( + DWORD CtrlType + ) +{ + _PHNDLR ctrl_action; + _PHNDLR *pctrl_action; + int sigcode; + + _mlock(_SIGNAL_LOCK); + + /* + * Identify the type of event and fetch the corresponding action + * description. + */ + + if ( CtrlType == CTRL_C_EVENT ) { + ctrl_action = *(pctrl_action = &ctrlc_action); + sigcode = SIGINT; + } + else { + ctrl_action = *(pctrl_action = &ctrlbreak_action); + sigcode = SIGBREAK; + } + + if ( ctrl_action == SIG_DFL ) { + /* + * return FALSE, indicating the event has NOT been handled + */ + _munlock(_SIGNAL_LOCK); + return FALSE; + } + + if ( ctrl_action != SIG_IGN ) { + /* + * Reset the action to be SIG_DFL and call the user's handler. + */ + *pctrl_action = SIG_DFL; + _munlock(_SIGNAL_LOCK); + (*ctrl_action)(sigcode); + } + else + /* + * SIG_IGN - nothing special to do except release the lock + */ + _munlock(_SIGNAL_LOCK); + + /* + * Return TRUE, indicating the event has been handled (which may + * mean it's being ignored) + */ + return TRUE; +} + + + +/*** +*_PHNDLR signal(signum, sigact) - Define a signal handler +* +*Purpose: +* The signal routine allows the user to define what action should +* be taken when various signals occur. The Win32/Dosx32 implementation +* supports seven signals, divided up into three general groups +* +* 1. Signals corresponding to OS exceptions. These are: +* SIGFPE +* SIGILL +* SIGSEGV +* Signal actions for these signals are installed by altering the +* XcptAction and SigAction fields for the appropriate entry in the +* exception-action table (XcptActTab[]). +* +* 2. Signals corresponding to ^C and ^Break. These are: +* SIGINT +* SIGBREAK +* Signal actions for these signals are installed by altering the +* _ctrlc_action and _ctrlbreak_action variables. +* +* 3. Signals which are implemented only in the runtime. That is, they +* occur only as the result of a call to raise(). +* SIGABRT +* SIGTERM +* +* +*Entry: +* int signum signal type. recognized signal types are: +* +* SIGABRT (ANSI) +* SIGBREAK +* SIGFPE (ANSI) +* SIGILL (ANSI) +* SIGINT (ANSI) +* SIGSEGV (ANSI) +* SIGTERM (ANSI) +* +* _PHNDLR sigact signal handling function or action code. the action +* codes are: +* +* SIG_DFL - take the default action, whatever that may +* be, upon receipt of this type type of signal. +* +* SIG_DIE - *** ILLEGAL *** +* special code used in the XcptAction field of an +* XcptActTab[] entry to indicate that the runtime is +* to terminate the process upon receipt of the exception. +* not accepted as a value for sigact. +* +* SIG_IGN - ignore this type of signal +* +* [function address] - transfer control to this address +* when a signal of this type occurs. +* +*Exit: +* Good return: +* Signal returns the previous value of the signal handling function +* (e.g., SIG_DFL, SIG_IGN, etc., or [function address]). This value is +* returned in DX:AX. +* +* Error return: +* Signal returns -1 and errno is set to EINVAL. The error return is +* generally taken if the user submits bogus input values. +* +*Exceptions: +* None. +* +*******************************************************************************/ + +_PHNDLR _CRTAPI1 signal( + int signum, + _PHNDLR sigact + ) +{ + struct _XCPT_ACTION *pxcptact; + _PHNDLR oldsigact; +#ifdef MTHREAD + _ptiddata ptd; +#endif + + /* + * Check for values of sigact supported on other platforms but not + * on this one. Also, make sure sigact is not SIG_DIE + */ + if ( (sigact == SIG_ACK) || (sigact == SIG_SGE) ) + goto sigreterror; + + /* + * Take care of all signals which do not correspond to exceptions + * in the host OS. Those are: + * + * SIGINT + * SIGBREAK + * SIGABRT + * SIGTERM + * + */ + if ( (signum == SIGINT) || (signum == SIGBREAK) || (signum == SIGABRT) + || (signum == SIGTERM) ) { + + _mlock(_SIGNAL_LOCK); + + /* + * if SIGINT or SIGBREAK, make sure the handler is installed + * to capture ^C and ^Break events. + */ + if ( ((signum == SIGINT) || (signum == SIGBREAK)) && + !ConsoleCtrlHandler_Installed ) + if ( SetConsoleCtrlHandler(ctrlevent_capture, TRUE) + == TRUE ) + ConsoleCtrlHandler_Installed = TRUE; + else { + _doserrno = GetLastError(); + _munlock(_SIGNAL_LOCK); + goto sigreterror; + } + + switch (signum) { + + case SIGINT: + oldsigact = ctrlc_action; + ctrlc_action = sigact; + break; + + case SIGBREAK: + oldsigact = ctrlbreak_action; + ctrlbreak_action = sigact; + break; + + case SIGABRT: + oldsigact = abort_action; + abort_action = sigact; + break; + + case SIGTERM: + oldsigact = term_action; + term_action = sigact; + break; + } + + _munlock(_SIGNAL_LOCK); + goto sigretok; + } + + /* + * If we reach here, signum is supposed to be one the signals which + * correspond to exceptions in the host OS. Those are: + * + * SIGFPE + * SIGILL + * SIGSEGV + */ + + /* + * Make sure signum is one of the remaining supported signals. + */ + if ( (signum != SIGFPE) && (signum != SIGILL) && (signum != SIGSEGV) ) + goto sigreterror; + + +#ifdef MTHREAD + /* + * Fetch the tid data table entry for this thread + */ + ptd = _getptd(); + + /* + * Check that there a per-thread instance of the exception-action + * table for this thread. if there isn't, create one. + */ + if ( ptd->_pxcptacttab == _XcptActTab ) + /* + * allocate space for an exception-action table + */ + if ( (ptd->_pxcptacttab = malloc(_XcptActTabSize)) + != NULL ) + /* + * initialize the table by copying over the contents + * of _XcptActTab[] + */ + (void) memcpy(ptd->_pxcptacttab, _XcptActTab, + _XcptActTabSize); + else + /* + * cannot create exception-action table, return + * error to caller + */ + goto sigreterror; + +#endif /* MTHREAD */ + + /* + * look up the proper entry in the exception-action table. note that + * if several exceptions are mapped to the same signal, this returns + * the pointer to first such entry in the exception action table. it + * is assumed that the other entries immediately follow this one. + */ +#ifdef MTHREAD + if ( (pxcptact = siglookup(signum, ptd->_pxcptacttab)) == NULL ) +#else /* not MTHREAD */ + if ( (pxcptact = siglookup(signum)) == NULL ) +#endif /* MTHREAD */ + goto sigreterror; + + /* + * SIGSEGV, SIGILL and SIGFPE all have more than one exception mapped + * to them. the code below depends on the exceptions corresponding to + * the same signal being grouped together in the exception-action + * table. + */ + + /* + * store old signal action code for return value + */ + oldsigact = pxcptact->XcptAction; + + /* + * loop through all entries corresponding to the + * given signal and update the SigAction and XcptAction + * fields as appropriate + * + * should add a test to make sure pxcptact never runs + * off the end of the table (works okay for now because + * of the order of the entries). + */ + while ( pxcptact->SigNum == signum ) { + /* + * take care of the SIG_IGN and SIG_DFL action + * codes + */ + pxcptact->XcptAction = sigact; + pxcptact++; + } + +sigretok: + return(oldsigact); + +sigreterror: + errno = EINVAL; + return(SIG_ERR); +} + +/*** +*int raise(signum) - Raise a signal +* +*Purpose: +* This routine raises a signal (i.e., performs the action currently +* defined for this signal). The action associated with the signal is +* evoked directly without going through intermediate dispatching or +* handling. +* +*Entry: +* int signum - signal type (e.g., SIGINT) +* +*Exit: +* returns 0 on good return, -1 on bad return. +* +*Exceptions: +* May not return. Raise has no control over the action +* routines defined for the various signals. Those routines may +* abort, terminate, etc. In particular, the default actions for +* certain signals will terminate the program. +* +*******************************************************************************/ + + +int _CRTAPI1 raise ( + int signum + ) +{ + _PHNDLR sigact; + _PHNDLR *psigact; + PEXCEPTION_POINTERS oldpxcptinfoptrs; + int oldfpecode; + +#ifdef MTHREAD + int siglock = 0; + _ptiddata ptd; +#endif + + switch (signum) { + + case SIGINT: + sigact = *(psigact = &ctrlc_action); +#ifdef MTHREAD + siglock++; +#endif + break; + + case SIGBREAK: + sigact = *(psigact = &ctrlbreak_action); +#ifdef MTHREAD + siglock++; +#endif + break; + + case SIGABRT: + sigact = *(psigact = &abort_action); +#ifdef MTHREAD + siglock++; +#endif + break; + + case SIGTERM: + sigact = *(psigact = &term_action); +#ifdef MTHREAD + siglock++; +#endif + break; + + case SIGFPE: + case SIGILL: + case SIGSEGV: +#ifdef MTHREAD + ptd = _getptd(); + sigact = *(psigact = &(siglookup( signum, + ptd->_pxcptacttab )->XcptAction)); +#else + sigact = *(psigact = &(siglookup( signum )-> + XcptAction)); +#endif + break; + + default: + /* + * unsupported signal, return an error + */ + return (-1); + } + +#ifdef MTHREAD + /* + * if signum is one of the 'process-wide' signals (i.e., SIGINT, + * SIGBREAK, SIGABRT or SIGTERM), assert _SIGNAL_LOCK. + */ + if ( siglock ) + _mlock(_SIGNAL_LOCK); +#endif + + /* + * If the current action is SIG_IGN, just return + */ + if ( sigact == SIG_IGN ) { + +#ifdef MTHREAD + if ( siglock ) + _munlock(_SIGNAL_LOCK); +#endif + return(0); + } + + /* + * If the current action is SIG_DFL, take the default action + */ + if ( sigact == SIG_DFL ) { + +#ifdef MTHREAD + if ( siglock ) + _munlock(_SIGNAL_LOCK); +#endif + /* + * The current default action for all of the supported + * signals is to terminate with an exit code of 3. + * + * BUG, BUG!!!! THIS IS ALMOST CERTAINLY THE WRONG EXIT + * CODE FOR SOME OF THE SIGNALS IN NT! + */ + _exit(3); + } + + /* + * From here on, sigact is assumed to be a pointer to a user-supplied + * handler. + */ + + /* + * For signals which correspond to exceptions, set the pointer + * to the EXCEPTION_POINTERS structure to NULL + */ + if ( (signum == SIGFPE) || (signum == SIGSEGV) || + (signum == SIGILL) ) { +#ifdef MTHREAD + oldpxcptinfoptrs = ptd->_tpxcptinfoptrs; + ptd->_tpxcptinfoptrs = NULL; +#else + oldpxcptinfoptrs = _pxcptinfoptrs; + _pxcptinfoptrs = NULL; +#endif + + /* + * If signum is SIGFPE, also set _fpecode to + * _FPE_EXPLICITGEN + */ + if ( signum == SIGFPE ) { +#ifdef MTHREAD + oldfpecode = ptd->_tfpecode; + ptd->_tfpecode = _FPE_EXPLICITGEN; +#else + oldfpecode = _fpecode; + _fpecode = _FPE_EXPLICITGEN; +#endif + } + } + + /* + * Reset the action to SIG_DFL and call the user specified handler + * routine. + */ + *psigact = SIG_DFL; + +#ifdef MTHREAD + if ( siglock ) + _munlock(_SIGNAL_LOCK); +#endif + + if ( signum == SIGFPE ) + /* + * Special hack to support old SIGFPE handlers which + * expect the value of _fpecode as the second argument. + */ +#ifdef MTHREAD + (*(void (* _CRTAPI1)(int,int))sigact)(SIGFPE, + ptd->_tfpecode); +#else + (*(void (* _CRTAPI1)(int,int))sigact)(SIGFPE, _fpecode); +#endif + else + (*sigact)(signum); + + /* + * For signals which correspond to exceptions, restore the pointer + * to the EXCEPTION_POINTERS structure. + */ + if ( (signum == SIGFPE) || (signum == SIGSEGV) || + (signum == SIGILL) ) { +#ifdef MTHREAD + ptd->_tpxcptinfoptrs = oldpxcptinfoptrs; +#else + _pxcptinfoptrs = oldpxcptinfoptrs; +#endif + + /* + * If signum is SIGFPE, also restore _fpecode + */ + if ( signum == SIGFPE ) +#ifdef MTHREAD + ptd->_tfpecode = oldfpecode; +#else + _fpecode = oldfpecode; +#endif + } + + return(0); +} + + +/*** +*struct _XCPT_ACTION *siglookup(int signum) - look up exception-action table +* entry for signal. +* +*Purpose: +* Find the first entry int _XcptActTab[] whose SigNum field is signum. +* +*Entry: +* int signum - C signal type (e.g., SIGINT) +* +*Exit: +* If successful, pointer to the table entry. If no such entry, NULL is +* returned. +* +*Exceptions: +* +*******************************************************************************/ + +#ifdef MTHREAD + +static struct _XCPT_ACTION * _CRTAPI3 siglookup ( + int signum, + struct _XCPT_ACTION *pxcptacttab + ) +{ + struct _XCPT_ACTION *pxcptact = pxcptacttab; + +#else /* not MTHREAD */ + +static struct _XCPT_ACTION * _CRTAPI3 siglookup(int signum) +{ + struct _XCPT_ACTION *pxcptact = _XcptActTab; + +#endif /* MTHREAD */ + /* + * walk thru the _xcptactab table looking for the proper entry. note + * that in the case where more than one exception corresponds to the + * same signal, the first such instance in the table is the one + * returned. + */ +#ifdef MTHREAD + + while ( (pxcptact->SigNum != signum) && (++pxcptact < + pxcptacttab + _XcptActTabCount) ) ; + +#else /* not MTHREAD */ + + while ( (pxcptact->SigNum != signum) && (++pxcptact < + _XcptActTab + _XcptActTabCount) ) ; + +#endif /* MTHREAD */ + + if ( pxcptact->SigNum == signum ) + /* + * found a table entry corresponding to the signal + */ + return(pxcptact); + else + /* + * found no table entry corresponding to the signal + */ + return(NULL); +} + +#ifdef MTHREAD + +/*** +*int *__fpecode(void) - return pointer to _fpecode field of the tidtable entry +* for the current thread +* +*Purpose: +* +*Entry: +* +*Exit: +* +*Exceptions: +* +*******************************************************************************/ + +int * _CRTAPI1 __fpecode ( + void + ) +{ + return( &(_getptd()->_tfpecode) ); +} + + +/*** +*void **__pxcptinfoptrs(void) - return pointer to _pxcptinfoptrs field of the +* tidtable entry for the current thread +* +*Purpose: +* +*Entry: +* +*Exit: +* +*Exceptions: +* +*******************************************************************************/ + +void ** _CRTAPI1 __pxcptinfoptrs ( + void + ) +{ + return( &(_getptd()->_tpxcptinfoptrs) ); +} + +#endif + +#endif /* _POSIX_ */ |