ReactOS 0.4.16-dev-835-gd769f56
signal.cpp
Go to the documentation of this file.
1//
2// signal.cpp
3//
4// Copyright (c) Microsoft Corporation. All rights reserved.
5//
6// signal(), raise(), and related functions
7//
8#include <corecrt_internal.h>
9#include <errno.h>
10#include <excpt.h>
11#include <float.h>
12#include <malloc.h>
13#include <signal.h>
14#include <stddef.h>
15#include <string.h>
16
17
18
19// Variables holding action codes (and code pointers) for SIGINT, SIGBRK,
20// SIGABRT and SIGTERM.
21//
22// note that the disposition (i.e., action to be taken upon receipt) of
23// these signals is defined on a per-process basis (not per-thread)!!
24static __crt_state_management::dual_state_global<__crt_signal_handler_t> ctrlc_action; // SIGINT
25static __crt_state_management::dual_state_global<__crt_signal_handler_t> ctrlbreak_action; // SIGBREAK
26static __crt_state_management::dual_state_global<__crt_signal_handler_t> abort_action; // SIGABRT
27static __crt_state_management::dual_state_global<__crt_signal_handler_t> term_action; // SIGTERM
28
29/*
30 * flag indicated whether or not a handler has been installed to capture
31 * ^C and ^Break events.
32 */
34
35#define _SIGHUP_IGNORE 1
36#define _SIGQUIT_IGNORE 3
37#define _SIGPIPE_IGNORE 13
38#define _SIGIOINT_IGNORE 16
39#define _SIGSTOP_IGNORE 17
40
41
42
43// Initializes the signal handler pointers to the encoded nullptr value.
44extern "C" void __cdecl __acrt_initialize_signal_handlers(void* const encoded_nullptr)
45{
46 // The encoded nullptr is SIG_DFL
47 ctrlc_action.initialize (reinterpret_cast<__crt_signal_handler_t>(encoded_nullptr));
48 ctrlbreak_action.initialize(reinterpret_cast<__crt_signal_handler_t>(encoded_nullptr));
49 abort_action.initialize (reinterpret_cast<__crt_signal_handler_t>(encoded_nullptr));
50 term_action.initialize (reinterpret_cast<__crt_signal_handler_t>(encoded_nullptr));
51}
52
53
54
55// Gets the address of the global action for one of the signals that has a
56// global action. Returns nullptr if the given signal does not have a global
57// action.
59{
60 switch (signum)
61 {
62 // CRT_REFACTOR TODO: PERFORMANCE: for OS mode, these might be able to be in the const data section, instead of in writeable page data.
63 case SIGINT: return &ctrlc_action.value();
64 case SIGBREAK: return &ctrlbreak_action.value();
65 case SIGABRT: return &abort_action.value();
66 case SIGABRT_COMPAT: return &abort_action.value();
67 case SIGTERM: return &term_action.value();
68 }
69
70 return nullptr;
71}
72
73
74
75// Looks up the exception-action table entry for a signal. This function finds
76// the first entry in the 'action_table' whose _signal_number field is 'signum'.
77// If no such entry is found, nullptr is returned.
79 int const signum,
80 __crt_signal_action_t* const action_table
81 ) throw()
82{
83 // Walk through the table looking for the proper entry. Note that in the
84 // case where more than one exception corresponds to the same signal, the
85 // first such instance in the table is the one returned.
86 for (__crt_signal_action_t* p = action_table; p != action_table + __acrt_signal_action_table_count; ++p)
87 if (p->_signal_number == signum)
88 return p;
89
90 // If we reached the end of the table, return nullptr:
91 return nullptr;
92}
93
94
95
96// Handles failures for signal().
97static __crt_signal_handler_t __cdecl signal_failed(int const signum) throw()
98{
99 switch (signum)
100 {
101 case _SIGHUP_IGNORE:
102 case _SIGQUIT_IGNORE:
103 case _SIGPIPE_IGNORE:
104 case _SIGIOINT_IGNORE:
105 case _SIGSTOP_IGNORE:
106 return SIG_ERR;
107
108 default:
109 errno = EINVAL;
110 return SIG_ERR;
111 }
112}
113
114// Enclaves have no console, thus also no signals specific to consoles.
115#ifdef _UCRT_ENCLAVE_BUILD
116
117__inline static BOOL is_unsupported_signal(int const signum, __crt_signal_handler_t const sigact)
118{
119 return (sigact == SIG_ACK || sigact == SIG_SGE || signum == SIGINT || signum == SIGBREAK);
120}
121
122__inline static BOOL is_console_signal(int const)
123{
124 return FALSE;
125}
126
127#else /* ^^^ _UCRT_ENCLAVE_BUILD ^^^ // vvv !_UCRT_ENCLAVE_BUILD vvv */
128
130{
131 return (sigact == SIG_ACK || sigact == SIG_SGE);
132}
133
134__inline static BOOL is_console_signal(int const signum)
135{
136 return (signum == SIGINT || signum == SIGBREAK);
137}
138
139#endif /* _UCRT_ENCLAVE_BUILD */
140
141/***
142*static BOOL WINAPI ctrlevent_capture(DWORD ctrl_type) - capture ^C and ^Break events
143*
144*Purpose:
145* Capture ^C and ^Break events from the console and dispose of them
146* according the values in ctrlc_action and ctrlbreak_action, resp.
147* This is the routine that evokes the user-defined action for SIGINT
148* (^C) or SIGBREAK (^Break) installed by a call to signal().
149*
150*Entry:
151* DWORD ctrl_type - indicates type of event, two values:
152* CTRL_C_EVENT
153* CTRL_BREAK_EVENT
154*
155*Exit:
156* Returns TRUE to indicate the event (signal) has been handled.
157* Otherwise, returns FALSE.
158*
159*Exceptions:
160*
161*******************************************************************************/
162
163static BOOL WINAPI ctrlevent_capture(DWORD const ctrl_type) throw()
164{
165 __crt_signal_handler_t ctrl_action = nullptr;
166 int signal_code = 0;
167
169 __try
170 {
171 __crt_signal_handler_t* pctrl_action;
172
173 // Identify the type of event and fetch the corresponding action
174 // description:
175 if (ctrl_type == CTRL_C_EVENT)
176 {
177 pctrl_action = &ctrlc_action.value();
178 ctrl_action = __crt_fast_decode_pointer(*pctrl_action);
179 signal_code = SIGINT;
180 }
181 else
182 {
183 pctrl_action = &ctrlbreak_action.value();
184 ctrl_action = __crt_fast_decode_pointer(*pctrl_action);
185 signal_code = SIGBREAK;
186 }
187
188 if (ctrl_action != SIG_DFL && ctrl_action != SIG_IGN)
189 {
190 // Reset the action to be SIG_DFL:
191 *pctrl_action = __crt_fast_encode_pointer(nullptr);
192 }
193 }
195 {
197 }
199
200 // The default signal action leaves the event unhandled, so return false to
201 // indicate such:
202 if (ctrl_action == SIG_DFL)
203 return FALSE;
204
205 // If the action is not to ignore the signal, then invoke the action:
206 if (ctrl_action != SIG_IGN)
207 (*ctrl_action)(signal_code);
208
209 // Then return TRUE to indicate the event has been handled (this may mean
210 // that the even is being ignored):
211 return TRUE;
212}
213
214
215/***
216*__crt_signal_handler_t signal(signum, sigact) - Define a signal handler
217*
218*Purpose:
219* The signal routine allows the user to define what action should
220* be taken when various signals occur. The Win32/Dosx32 implementation
221* supports seven signals, divided up into three general groups
222*
223* 1. Signals corresponding to OS exceptions. These are:
224* SIGFPE
225* SIGILL
226* SIGSEGV
227* Signal actions for these signals are installed by altering the
228* _action and SigAction fields for the appropriate entry in the
229* exception-action table (XcptActTab[]).
230*
231* 2. Signals corresponding to ^C and ^Break. These are:
232* SIGINT
233* SIGBREAK
234* Signal actions for these signals are installed by altering the
235* _ctrlc_action and _ctrlbreak_action variables.
236*
237* 3. Signals which are implemented only in the runtime. That is, they
238* occur only as the result of a call to raise().
239* SIGABRT
240* SIGTERM
241*
242*
243*Entry:
244* int signum signal type. recognized signal types are:
245*
246* SIGABRT (ANSI)
247* SIGBREAK
248* SIGFPE (ANSI)
249* SIGILL (ANSI)
250* SIGINT (ANSI)
251* SIGSEGV (ANSI)
252* SIGTERM (ANSI)
253* SIGABRT_COMPAT
254*
255* __crt_signal_handler_t sigact signal handling function or action code. the action
256* codes are:
257*
258* SIG_DFL - take the default action, whatever that may
259* be, upon receipt of this type type of signal.
260*
261* SIG_DIE - *** ILLEGAL ***
262* special code used in the _action field of an
263* XcptActTab[] entry to indicate that the runtime is
264* to terminate the process upon receipt of the exception.
265* not accepted as a value for sigact.
266*
267* SIG_IGN - ignore this type of signal
268*
269* [function address] - transfer control to this address
270* when a signal of this type occurs.
271*
272*Exit:
273* Good return:
274* Signal returns the previous value of the signal handling function
275* (e.g., SIG_DFL, SIG_IGN, etc., or [function address]). This value is
276* returned in DX:AX.
277*
278* Error return:
279* Signal returns -1 and errno is set to EINVAL. The error return is
280* generally taken if the user submits bogus input values.
281*
282*Exceptions:
283* None.
284*
285*******************************************************************************/
286
288{
289 // Check for signal actions that are supported on other platforms but not on
290 // this one, and make sure the action is not SIG_DIE:
291 if (is_unsupported_signal(signum, sigact))
292 return signal_failed(signum);
293
294 // First, handle the case where the signal does not correspond to an
295 // exception in the host OS:
296 if (signum == SIGINT ||
297 signum == SIGBREAK ||
298 signum == SIGABRT ||
299 signum == SIGABRT_COMPAT ||
300 signum == SIGTERM)
301 {
302 bool set_console_ctrl_error = false;
303 __crt_signal_handler_t old_action = nullptr;
304
306 __try
307 {
308 // If the signal is SIGINT or SIGBREAK make sure the handler is
309 // installed to capture ^C and ^Break events:
310 // C4127: conditional expression is constant
311#pragma warning( suppress: 4127 )
313 {
315 {
317 }
318 else
319 {
321 set_console_ctrl_error = true;
322 }
323 }
324
325 __crt_signal_handler_t* const action_pointer = get_global_action_nolock(signum);
326 if (action_pointer != nullptr)
327 {
328 old_action = __crt_fast_decode_pointer(*action_pointer);
329 if (sigact != SIG_GET)
330 *action_pointer = __crt_fast_encode_pointer(sigact);
331 }
332 }
334 {
336 }
338
339 if (set_console_ctrl_error)
340 return signal_failed(signum);
341
342 return old_action;
343 }
344
345
346 // If we reach here, signum is supposed to be one of the signals which
347 // correspond to exceptions on the host OS. If it's not one of these,
348 // fail and return immediately:
349 if (signum != SIGFPE && signum != SIGILL && signum != SIGSEGV)
350 return signal_failed(signum);
351
353 if (ptd == nullptr)
354 return signal_failed(signum);
355
356 // Check that there is a per-thread instance of the exception-action table
357 // for this thread. If there isn't, create one:
358 if (ptd->_pxcptacttab == __acrt_exception_action_table)
359 {
360 // Allocate space for an exception-action table:
362 if (ptd->_pxcptacttab == nullptr)
363 return signal_failed(signum);
364
365 // Initialize the table by copying the contents of __acrt_exception_action_table:
367 }
368
369 // Look up the proper entry in the exception-action table. Note that if
370 // several exceptions are mapped to the same signal, this returns the
371 // pointer to first such entry in the exception action table. It is assumed
372 // that the other entries immediately follow this one.
373 __crt_signal_action_t* const xcpt_action = siglookup(signum, ptd->_pxcptacttab);
374 if (xcpt_action == nullptr)
375 return signal_failed(signum);
376
377 // SIGSEGV, SIGILL and SIGFPE all have more than one exception mapped to
378 // them. The code below depends on the exceptions corresponding to the same
379 // signal being grouped together in the exception-action table.
380
381 __crt_signal_handler_t const old_action = xcpt_action->_action;
382
383 // If we are not just getting the currently installed action, loop through
384 // all the entries corresponding to the given signal and update them as
385 // appropriate:
386 if (sigact != SIG_GET)
387 {
389
390 // Iterate until we reach the end of the table or we reach the end of
391 // the range of actions for this signal, whichever comes first:
392 for (__crt_signal_action_t* p = xcpt_action; p != last && p->_signal_number == signum; ++p)
393 {
394 p->_action = sigact;
395 }
396 }
397
398 return old_action;
399}
400
401
402
403/***
404*int raise(signum) - Raise a signal
405*
406*Purpose:
407* This routine raises a signal (i.e., performs the action currently
408* defined for this signal). The action associated with the signal is
409* evoked directly without going through intermediate dispatching or
410* handling.
411*
412*Entry:
413* int signum - signal type (e.g., SIGINT)
414*
415*Exit:
416* returns 0 on good return, -1 on bad return.
417*
418*Exceptions:
419* May not return. Raise has no control over the action
420* routines defined for the various signals. Those routines may
421* abort, terminate, etc. In particular, the default actions for
422* certain signals will terminate the program.
423*
424*******************************************************************************/
425extern "C" int __cdecl raise(int const signum)
426{
427 __acrt_ptd* ptd = nullptr;
428 int old_fpecode = 0;
429
430 __crt_signal_handler_t* action_pointer = nullptr;
431 bool action_is_global = true;
432 switch (signum)
433 {
434 case SIGINT:
435 case SIGBREAK:
436 case SIGABRT:
437 case SIGABRT_COMPAT:
438 case SIGTERM:
439 action_pointer = get_global_action_nolock(signum);;
440 break;
441
442 case SIGFPE:
443 case SIGILL:
444 case SIGSEGV:
445 {
447 if (ptd == nullptr)
448 return -1;
449
450 __crt_signal_action_t* const local_action = siglookup(signum, ptd->_pxcptacttab);
451 _VALIDATE_RETURN(local_action != nullptr, EINVAL, -1);
452 action_pointer = &local_action->_action;
453 action_is_global = false;
454 break;
455 }
456 default:
457 // unsupported signal, return an error
458 _VALIDATE_RETURN(("Invalid signal or error", 0), EINVAL, -1);
459 }
460
461
462 PEXCEPTION_POINTERS old_pxcptinfoptrs = nullptr;
463
464 // If the action is global, we must acquire the lock before accessing it:
465 if (action_is_global)
467
469 bool return0 = false;
470 __try
471 {
472 // Global function pointers are encoded; per-thread pointers are not:
473 action = action_is_global ? __crt_fast_decode_pointer(*action_pointer) : *action_pointer;
474
475 // If the current action is SIG_IGN, just return:
476 return0 = action == SIG_IGN;
477 if (return0)
478 __leave;
479
480 // If the current action is SIG_DFL, take the default action. The current
481 // default action for all of the supported signals is to terminate with an
482 // exit code of 3:
483 if (action == SIG_DFL)
484 {
485 // Be sure to unlock before entering the exit code. The exit function
486 // does not return.
487 if (action_is_global)
489
490 _exit(3);
491 }
492
493 // For signals that correspond to exceptions, set the pointer to the
494 // EXCEPTION_POINTERS structure to nullptr:
495 if (signum == SIGFPE || signum == SIGSEGV || signum == SIGILL)
496 {
497 old_pxcptinfoptrs = ptd->_tpxcptinfoptrs;
498 ptd->_tpxcptinfoptrs = nullptr;
499
500 // If the signal is SIGFPE, also set _fpecode to _FPE_EXPLICITGEN:
501 if ( signum == SIGFPE )
502 {
503 old_fpecode = _fpecode;
505 }
506 }
507
508 // Reset the action to SIG_DFL before calling the user-specified handler.
509 // For SIGFPE, we must reset the action for all of the FP exceptions:
510 if (signum == SIGFPE)
511 {
514
515 for (__crt_signal_action_t* p = first; p != last; ++p)
516 {
517 p->_action = SIG_DFL;
518 }
519 }
520 else
521 {
522 *action_pointer = __crt_fast_encode_pointer(nullptr);
523 }
524 }
526 {
527 if (action_is_global)
529 }
531
532 if (return0)
533 return 0;
534
535 // Call the user-specified handler routine. For SIGFPE, we have special
536 // code to support old handlers which expect the value of _fpecode as the
537 // second argument:
538 if (signum == SIGFPE)
539 {
540 reinterpret_cast<void(__cdecl*)(int,int)>(action)(SIGFPE, _fpecode);
541 }
542 else
543 {
544 action(signum);
545 }
546
547
548 // For signals that correspond to exceptions, restore the pointer to the
549 // EXCEPTION_POINTERS structure:
550 if (signum == SIGFPE || signum == SIGSEGV || signum == SIGILL)
551 {
552 ptd->_tpxcptinfoptrs = old_pxcptinfoptrs;
553
554 // If signum is SIGFPE, also restore _fpecode
555 if (signum == SIGFPE)
556 _fpecode = old_fpecode;
557 }
558
559 return 0;
560}
561
562
563// Gets the SIGABRT signal handling function
565{
566 return __acrt_lock_and_call(__acrt_signal_lock, []
567 {
568 return __crt_fast_decode_pointer(abort_action.value());
569 });
570}
571
572// Gets the FPE code for the current thread
573extern "C" int* __cdecl __fpecode()
574{
575 return &__acrt_getptd()->_tfpecode;
576}
577
578// Returns a pointer to the signal handlers for the current thread
579extern "C" void** __cdecl __pxcptinfoptrs()
580{
581 return reinterpret_cast<void**>(&__acrt_getptd()->_tpxcptinfoptrs);
582}
void _exit(int exitcode)
Definition: _exit.c:25
#define __inline
Definition: _wctype.cpp:15
#define EINVAL
Definition: acclib.h:90
#define __cdecl
Definition: accygwin.h:79
__acrt_ptd *__cdecl __acrt_getptd(void)
void __cdecl __acrt_unlock(_In_ __acrt_lock_id lock)
Definition: locks.cpp:57
size_t const __acrt_signal_action_first_fpe_index
@ __acrt_signal_lock
void(__cdecl * __crt_signal_handler_t)(int)
size_t const __acrt_signal_action_fpe_count
struct __crt_signal_action_t const __acrt_exception_action_table[]
size_t const __acrt_signal_action_table_count
__acrt_ptd *__cdecl __acrt_getptd_noexit(void)
size_t const __acrt_signal_action_table_size
#define _VALIDATE_RETURN(expr, errorcode, retexpr)
#define SIG_DFL
Definition: signal.h:47
#define SIG_ERR
Definition: signal.h:52
#define SIGINT
Definition: signal.h:23
#define SIGILL
Definition: signal.h:25
#define SIGABRT_COMPAT
Definition: signal.h:43
#define SIGTERM
Definition: signal.h:39
#define SIGFPE
Definition: signal.h:30
#define SIG_SGE
Definition: signal.h:50
#define SIGABRT
Definition: signal.h:28
#define SIG_ACK
Definition: signal.h:51
#define SIG_IGN
Definition: signal.h:48
#define SIG_GET
Definition: signal.h:49
#define SIGSEGV
Definition: signal.h:33
#define SIGBREAK
Definition: signal.h:40
_In_ size_t const _In_ int _In_ bool const _In_ unsigned const _In_ __acrt_rounding_mode const _Inout_ __crt_cached_ptd_host & ptd
Definition: cvt.cpp:355
__acrt_lock(__acrt_heap_lock)
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
BOOL WINAPI DECLSPEC_HOTPATCH SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine, BOOL Add)
Definition: console.c:2109
const WCHAR * action
Definition: action.c:7509
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
const GLint * first
Definition: glext.h:5794
GLfloat GLfloat p
Definition: glext.h:8902
#define _FPE_EXPLICITGEN
Definition: float.h:109
#define _fpecode
Definition: float.h:157
#define _doserrno
Definition: stdlib.h:131
#define _malloc_crt
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
static UINT UINT last
Definition: font.c:45
#define __try
Definition: pseh2_64.h:172
#define __leave
Definition: pseh2_64.h:176
#define __endtry
Definition: pseh2_64.h:175
#define __finally
Definition: pseh2_64.h:174
#define errno
Definition: errno.h:18
int signal
Definition: except.c:84
void **__cdecl __pxcptinfoptrs()
Definition: signal.cpp:579
#define _SIGQUIT_IGNORE
Definition: signal.cpp:36
static bool console_ctrl_handler_installed
Definition: signal.cpp:33
int *__cdecl __fpecode()
Definition: signal.cpp:573
static __crt_state_management::dual_state_global< __crt_signal_handler_t > term_action
Definition: signal.cpp:27
static __crt_state_management::dual_state_global< __crt_signal_handler_t > ctrlbreak_action
Definition: signal.cpp:25
#define _SIGSTOP_IGNORE
Definition: signal.cpp:39
#define _SIGHUP_IGNORE
Definition: signal.cpp:35
__crt_signal_handler_t __cdecl __acrt_get_sigabrt_handler()
Definition: signal.cpp:564
static __crt_signal_handler_t __cdecl signal_failed(int const signum)
Definition: signal.cpp:97
static __inline BOOL is_unsupported_signal(int const, __crt_signal_handler_t const sigact)
Definition: signal.cpp:129
#define _SIGIOINT_IGNORE
Definition: signal.cpp:38
static __crt_state_management::dual_state_global< __crt_signal_handler_t > ctrlc_action
Definition: signal.cpp:24
static BOOL WINAPI ctrlevent_capture(DWORD const ctrl_type)
Definition: signal.cpp:163
void __cdecl __acrt_initialize_signal_handlers(void *const encoded_nullptr)
Definition: signal.cpp:44
static __inline BOOL is_console_signal(int const signum)
Definition: signal.cpp:134
int __cdecl raise(int const signum)
Definition: signal.cpp:425
#define _SIGPIPE_IGNORE
Definition: signal.cpp:37
static __crt_signal_action_t *__cdecl siglookup(int const signum, __crt_signal_action_t *const action_table)
Definition: signal.cpp:78
static __crt_state_management::dual_state_global< __crt_signal_handler_t > abort_action
Definition: signal.cpp:26
static __crt_signal_handler_t *__cdecl get_global_action_nolock(int const signum)
Definition: signal.cpp:58
EXCEPTION_POINTERS * _tpxcptinfoptrs
__crt_signal_handler_t _action
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define CTRL_C_EVENT
Definition: wincon.h:68
#define WINAPI
Definition: msvc.h:6