Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583//// signal.cpp//// Copyright (c) Microsoft Corporation. All rights reserved.//// signal(), raise(), and related functions//#include <corecrt_internal.h>#include <errno.h>#include <excpt.h>#include <float.h>#include <malloc.h>#include <signal.h>#include <stddef.h>#include <string.h>
// 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 __crt_state_management::dual_state_global<__crt_signal_handler_t> ctrlc_action; // SIGINTstatic __crt_state_management::dual_state_global<__crt_signal_handler_t> ctrlbreak_action; // SIGBREAKstatic __crt_state_management::dual_state_global<__crt_signal_handler_t> abort_action; // SIGABRTstatic __crt_state_management::dual_state_global<__crt_signal_handler_t> term_action; // SIGTERM
/* * flag indicated whether or not a handler has been installed to capture * ^C and ^Break events. */static bool console_ctrl_handler_installed = false;
#define _SIGHUP_IGNORE 1#define _SIGQUIT_IGNORE 3#define _SIGPIPE_IGNORE 13#define _SIGIOINT_IGNORE 16#define _SIGSTOP_IGNORE 17
// Initializes the signal handler pointers to the encoded nullptr value.extern "C" void __cdecl __acrt_initialize_signal_handlers(void* const encoded_nullptr){ // The encoded nullptr is SIG_DFL ctrlc_action.initialize (reinterpret_cast<__crt_signal_handler_t>(encoded_nullptr)); ctrlbreak_action.initialize(reinterpret_cast<__crt_signal_handler_t>(encoded_nullptr)); abort_action.initialize (reinterpret_cast<__crt_signal_handler_t>(encoded_nullptr)); term_action.initialize (reinterpret_cast<__crt_signal_handler_t>(encoded_nullptr));}
// Gets the address of the global action for one of the signals that has a// global action. Returns nullptr if the given signal does not have a global// action.static __crt_signal_handler_t* __cdecl get_global_action_nolock(int const signum) throw(){ switch (signum) { // CRT_REFACTOR TODO: PERFORMANCE: for OS mode, these might be able to be in the const data section, instead of in writeable page data. case SIGINT: return &ctrlc_action.value(); case SIGBREAK: return &ctrlbreak_action.value(); case SIGABRT: return &abort_action.value(); case SIGABRT_COMPAT: return &abort_action.value(); case SIGTERM: return &term_action.value(); }
return nullptr;}
// Looks up the exception-action table entry for a signal. This function finds// the first entry in the 'action_table' whose _signal_number field is 'signum'.// If no such entry is found, nullptr is returned.static __crt_signal_action_t* __cdecl siglookup( int const signum, __crt_signal_action_t* const action_table ) throw(){ // Walk through the 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. for (__crt_signal_action_t* p = action_table; p != action_table + __acrt_signal_action_table_count; ++p) if (p->_signal_number == signum) return p;
// If we reached the end of the table, return nullptr: return nullptr;}
// Handles failures for signal().static __crt_signal_handler_t __cdecl signal_failed(int const signum) throw(){ switch (signum) { case _SIGHUP_IGNORE: case _SIGQUIT_IGNORE: case _SIGPIPE_IGNORE: case _SIGIOINT_IGNORE: case _SIGSTOP_IGNORE: return SIG_ERR;
default: errno = EINVAL; return SIG_ERR; }}
// Enclaves have no console, thus also no signals specific to consoles.#ifdef _UCRT_ENCLAVE_BUILD
__inline static BOOL is_unsupported_signal(int const signum, __crt_signal_handler_t const sigact){ return (sigact == SIG_ACK || sigact == SIG_SGE || signum == SIGINT || signum == SIGBREAK);}
__inline static BOOL is_console_signal(int const){ return FALSE;}
#else /* ^^^ _UCRT_ENCLAVE_BUILD ^^^ // vvv !_UCRT_ENCLAVE_BUILD vvv */
__inline static BOOL is_unsupported_signal(int const, __crt_signal_handler_t const sigact){ return (sigact == SIG_ACK || sigact == SIG_SGE);}
__inline static BOOL is_console_signal(int const signum){ return (signum == SIGINT || signum == SIGBREAK);}
#endif /* _UCRT_ENCLAVE_BUILD */
/****static BOOL WINAPI ctrlevent_capture(DWORD ctrl_type) - 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 ctrl_type - 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 const ctrl_type) throw(){ __crt_signal_handler_t ctrl_action = nullptr; int signal_code = 0;
__acrt_lock(__acrt_signal_lock); __try { __crt_signal_handler_t* pctrl_action;
// Identify the type of event and fetch the corresponding action // description: if (ctrl_type == CTRL_C_EVENT) { pctrl_action = &ctrlc_action.value(); ctrl_action = __crt_fast_decode_pointer(*pctrl_action); signal_code = SIGINT; } else { pctrl_action = &ctrlbreak_action.value(); ctrl_action = __crt_fast_decode_pointer(*pctrl_action); signal_code = SIGBREAK; }
if (ctrl_action != SIG_DFL && ctrl_action != SIG_IGN) { // Reset the action to be SIG_DFL: *pctrl_action = __crt_fast_encode_pointer(nullptr); } } __finally { __acrt_unlock(__acrt_signal_lock); } __endtry
// The default signal action leaves the event unhandled, so return false to // indicate such: if (ctrl_action == SIG_DFL) return FALSE;
// If the action is not to ignore the signal, then invoke the action: if (ctrl_action != SIG_IGN) (*ctrl_action)(signal_code);
// Then return TRUE to indicate the event has been handled (this may mean // that the even is being ignored): return TRUE;}
/****__crt_signal_handler_t 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* _action 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)* SIGABRT_COMPAT** __crt_signal_handler_t 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 _action 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.********************************************************************************/
extern "C" __crt_signal_handler_t __cdecl signal(int signum, __crt_signal_handler_t sigact){ // Check for signal actions that are supported on other platforms but not on // this one, and make sure the action is not SIG_DIE: if (is_unsupported_signal(signum, sigact)) return signal_failed(signum);
// First, handle the case where the signal does not correspond to an // exception in the host OS: if (signum == SIGINT || signum == SIGBREAK || signum == SIGABRT || signum == SIGABRT_COMPAT || signum == SIGTERM) { bool set_console_ctrl_error = false; __crt_signal_handler_t old_action = nullptr;
__acrt_lock(__acrt_signal_lock); __try { // If the signal is SIGINT or SIGBREAK make sure the handler is // installed to capture ^C and ^Break events: // C4127: conditional expression is constant#pragma warning( suppress: 4127 ) if (is_console_signal(signum) && !console_ctrl_handler_installed) { if (SetConsoleCtrlHandler(ctrlevent_capture, TRUE)) { console_ctrl_handler_installed = true; } else { _doserrno = GetLastError(); set_console_ctrl_error = true; } }
__crt_signal_handler_t* const action_pointer = get_global_action_nolock(signum); if (action_pointer != nullptr) { old_action = __crt_fast_decode_pointer(*action_pointer); if (sigact != SIG_GET) *action_pointer = __crt_fast_encode_pointer(sigact); } } __finally { __acrt_unlock(__acrt_signal_lock); } __endtry
if (set_console_ctrl_error) return signal_failed(signum);
return old_action; }
// If we reach here, signum is supposed to be one of the signals which // correspond to exceptions on the host OS. If it's not one of these, // fail and return immediately: if (signum != SIGFPE && signum != SIGILL && signum != SIGSEGV) return signal_failed(signum);
__acrt_ptd* const ptd = __acrt_getptd_noexit(); if (ptd == nullptr) return signal_failed(signum);
// Check that there is a per-thread instance of the exception-action table // for this thread. If there isn't, create one: if (ptd->_pxcptacttab == __acrt_exception_action_table) { // Allocate space for an exception-action table: ptd->_pxcptacttab = static_cast<__crt_signal_action_t*>(_malloc_crt(__acrt_signal_action_table_size)); if (ptd->_pxcptacttab == nullptr) return signal_failed(signum);
// Initialize the table by copying the contents of __acrt_exception_action_table: memcpy(ptd->_pxcptacttab, __acrt_exception_action_table, __acrt_signal_action_table_size); }
// 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. __crt_signal_action_t* const xcpt_action = siglookup(signum, ptd->_pxcptacttab); if (xcpt_action == nullptr) return signal_failed(signum);
// 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.
__crt_signal_handler_t const old_action = xcpt_action->_action;
// If we are not just getting the currently installed action, loop through // all the entries corresponding to the given signal and update them as // appropriate: if (sigact != SIG_GET) { __crt_signal_action_t* const last = ptd->_pxcptacttab + __acrt_signal_action_table_count;
// Iterate until we reach the end of the table or we reach the end of // the range of actions for this signal, whichever comes first: for (__crt_signal_action_t* p = xcpt_action; p != last && p->_signal_number == signum; ++p) { p->_action = sigact; } }
return old_action;}
/****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.********************************************************************************/extern "C" int __cdecl raise(int const signum){ __acrt_ptd* ptd = nullptr; int old_fpecode = 0;
__crt_signal_handler_t* action_pointer = nullptr; bool action_is_global = true; switch (signum) { case SIGINT: case SIGBREAK: case SIGABRT: case SIGABRT_COMPAT: case SIGTERM: action_pointer = get_global_action_nolock(signum);; break;
case SIGFPE: case SIGILL: case SIGSEGV: { ptd = __acrt_getptd_noexit(); if (ptd == nullptr) return -1;
__crt_signal_action_t* const local_action = siglookup(signum, ptd->_pxcptacttab); _VALIDATE_RETURN(local_action != nullptr, EINVAL, -1); action_pointer = &local_action->_action; action_is_global = false; break; } default: // unsupported signal, return an error _VALIDATE_RETURN(("Invalid signal or error", 0), EINVAL, -1); }
PEXCEPTION_POINTERS old_pxcptinfoptrs = nullptr;
// If the action is global, we must acquire the lock before accessing it: if (action_is_global) __acrt_lock(__acrt_signal_lock);
__crt_signal_handler_t action = nullptr; bool return0 = false; __try { // Global function pointers are encoded; per-thread pointers are not: action = action_is_global ? __crt_fast_decode_pointer(*action_pointer) : *action_pointer;
// If the current action is SIG_IGN, just return: return0 = action == SIG_IGN; if (return0) __leave;
// If the current action is SIG_DFL, take the default action. The current // default action for all of the supported signals is to terminate with an // exit code of 3: if (action == SIG_DFL) { // Be sure to unlock before entering the exit code. The exit function // does not return. if (action_is_global) __acrt_unlock(__acrt_signal_lock);
_exit(3); }
// For signals that correspond to exceptions, set the pointer to the // EXCEPTION_POINTERS structure to nullptr: if (signum == SIGFPE || signum == SIGSEGV || signum == SIGILL) { old_pxcptinfoptrs = ptd->_tpxcptinfoptrs; ptd->_tpxcptinfoptrs = nullptr;
// If the signal is SIGFPE, also set _fpecode to _FPE_EXPLICITGEN: if ( signum == SIGFPE ) { old_fpecode = _fpecode; _fpecode = _FPE_EXPLICITGEN; } }
// Reset the action to SIG_DFL before calling the user-specified handler. // For SIGFPE, we must reset the action for all of the FP exceptions: if (signum == SIGFPE) { __crt_signal_action_t* const first = ptd->_pxcptacttab + __acrt_signal_action_first_fpe_index; __crt_signal_action_t* const last = first + __acrt_signal_action_fpe_count;
for (__crt_signal_action_t* p = first; p != last; ++p) { p->_action = SIG_DFL; } } else { *action_pointer = __crt_fast_encode_pointer(nullptr); } } __finally { if (action_is_global) __acrt_unlock(__acrt_signal_lock); } __endtry
if (return0) return 0;
// Call the user-specified handler routine. For SIGFPE, we have special // code to support old handlers which expect the value of _fpecode as the // second argument: if (signum == SIGFPE) { reinterpret_cast<void(__cdecl*)(int,int)>(action)(SIGFPE, _fpecode); } else { action(signum); }
// For signals that correspond to exceptions, restore the pointer to the // EXCEPTION_POINTERS structure: if (signum == SIGFPE || signum == SIGSEGV || signum == SIGILL) { ptd->_tpxcptinfoptrs = old_pxcptinfoptrs;
// If signum is SIGFPE, also restore _fpecode if (signum == SIGFPE) _fpecode = old_fpecode; }
return 0;}
// Gets the SIGABRT signal handling functionextern "C" __crt_signal_handler_t __cdecl __acrt_get_sigabrt_handler(){ return __acrt_lock_and_call(__acrt_signal_lock, [] { return __crt_fast_decode_pointer(abort_action.value()); });}
// Gets the FPE code for the current threadextern "C" int* __cdecl __fpecode(){ return &__acrt_getptd()->_tfpecode;}
// Returns a pointer to the signal handlers for the current threadextern "C" void** __cdecl __pxcptinfoptrs(){ return reinterpret_cast<void**>(&__acrt_getptd()->_tpxcptinfoptrs);}