summaryrefslogtreecommitdiffstats
path: root/private/crt32/misc/winsig.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/crt32/misc/winsig.c')
-rw-r--r--private/crt32/misc/winsig.c709
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_ */