Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

756 lines
22 KiB

  1. /***
  2. *winsig.c - C signal support
  3. *
  4. * Copyright (c) 1991-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * Defines signal(), raise() and supporting functions.
  8. *
  9. *Revision History:
  10. * 10-21-91 GJF Signal for Win32 and Dosx32. Copied from old signal.c
  11. * (the Cruiser implementation with some revisions for
  12. * Win32), then extensively rewritten.
  13. * 11-08-91 GJF Cleaned up header files usage.
  14. * 12-13-91 GJF Fixed multi-thread build.
  15. * 09-30-92 SRW Add WINAPI keyword to CtrlC handler
  16. * 02-17-93 GJF Changed for new _getptd().
  17. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  18. * 07-29-93 GJF Must reset the action for all FPE-s to SIG_DFL when
  19. * SIGFPE is raised.
  20. * 09-06-94 CFW Replace MTHREAD with _MT.
  21. * 01-10-95 CFW Debug CRT allocs.
  22. * 08-16-96 GJF Fixed overruns of _XctActTab. Also, detab-ed.
  23. * 08-21-96 GJF Fixed _MT part of overrun fix.
  24. * 03-05-98 GJF Exception-safe locking.
  25. *
  26. *******************************************************************************/
  27. #ifndef _POSIX_
  28. #include <cruntime.h>
  29. #include <errno.h>
  30. #include <float.h>
  31. #include <malloc.h>
  32. #include <mtdll.h>
  33. #include <oscalls.h>
  34. #include <signal.h>
  35. #include <stddef.h>
  36. #include <stdlib.h>
  37. #include <string.h>
  38. #include <dbgint.h>
  39. /*
  40. * look up the first entry in the exception-action table corresponding to
  41. * the given signal
  42. */
  43. #ifdef _MT
  44. static struct _XCPT_ACTION * __cdecl siglookup(int, struct _XCPT_ACTION *);
  45. #else /* not _MT */
  46. static struct _XCPT_ACTION * __cdecl siglookup(int);
  47. #endif /* _MT */
  48. /*
  49. * variables holding action codes (and code pointers) for SIGINT, SIGBRK,
  50. * SIGABRT and SIGTERM.
  51. *
  52. * note that the disposition (i.e., action to be taken upon receipt) of
  53. * these signals is defined on a per-process basis (not per-thread)!!
  54. */
  55. static _PHNDLR ctrlc_action = SIG_DFL; /* SIGINT */
  56. static _PHNDLR ctrlbreak_action = SIG_DFL; /* SIGBREAK */
  57. static _PHNDLR abort_action = SIG_DFL; /* SIGABRT */
  58. static _PHNDLR term_action = SIG_DFL; /* SIGTERM */
  59. /*
  60. * flag indicated whether or not a handler has been installed to capture
  61. * ^C and ^Break events.
  62. */
  63. static int ConsoleCtrlHandler_Installed = 0;
  64. /***
  65. *static BOOL WINAPI ctrlevent_capture(DWORD CtrlType) - capture ^C and ^Break events
  66. *
  67. *Purpose:
  68. * Capture ^C and ^Break events from the console and dispose of them
  69. * according the values in ctrlc_action and ctrlbreak_action, resp.
  70. * This is the routine that evokes the user-defined action for SIGINT
  71. * (^C) or SIGBREAK (^Break) installed by a call to signal().
  72. *
  73. *Entry:
  74. * DWORD CtrlType - indicates type of event, two values:
  75. * CTRL_C_EVENT
  76. * CTRL_BREAK_EVENT
  77. *
  78. *Exit:
  79. * Returns TRUE to indicate the event (signal) has been handled.
  80. * Otherwise, returns FALSE.
  81. *
  82. *Exceptions:
  83. *
  84. *******************************************************************************/
  85. static BOOL WINAPI ctrlevent_capture (
  86. DWORD CtrlType
  87. )
  88. {
  89. _PHNDLR ctrl_action;
  90. _PHNDLR *pctrl_action;
  91. int sigcode;
  92. #ifdef _MT
  93. _mlock(_SIGNAL_LOCK);
  94. __try {
  95. #endif /* _MT */
  96. /*
  97. * Identify the type of event and fetch the corresponding action
  98. * description.
  99. */
  100. if ( CtrlType == CTRL_C_EVENT ) {
  101. ctrl_action = *(pctrl_action = &ctrlc_action);
  102. sigcode = SIGINT;
  103. }
  104. else {
  105. ctrl_action = *(pctrl_action = &ctrlbreak_action);
  106. sigcode = SIGBREAK;
  107. }
  108. #ifdef _MT
  109. if ( !(ctrl_action == SIG_DFL) && !(ctrl_action == SIG_IGN) )
  110. /*
  111. * Reset the action to be SIG_DFL
  112. */
  113. *pctrl_action = SIG_DFL;
  114. }
  115. __finally {
  116. _munlock(_SIGNAL_LOCK);
  117. }
  118. #endif /* _MT */
  119. if ( ctrl_action == SIG_DFL )
  120. /*
  121. * return FALSE, indicating the event has NOT been handled
  122. */
  123. return FALSE;
  124. if ( ctrl_action != SIG_IGN ) {
  125. #ifndef _MT
  126. /*
  127. * Reset the action to be SIG_DFL and call the user's handler.
  128. */
  129. *pctrl_action = SIG_DFL;
  130. #endif /* ndef _MT */
  131. (*ctrl_action)(sigcode);
  132. }
  133. /*
  134. * Return TRUE, indicating the event has been handled (which may
  135. * mean it's being ignored)
  136. */
  137. return TRUE;
  138. }
  139. /***
  140. *_PHNDLR signal(signum, sigact) - Define a signal handler
  141. *
  142. *Purpose:
  143. * The signal routine allows the user to define what action should
  144. * be taken when various signals occur. The Win32/Dosx32 implementation
  145. * supports seven signals, divided up into three general groups
  146. *
  147. * 1. Signals corresponding to OS exceptions. These are:
  148. * SIGFPE
  149. * SIGILL
  150. * SIGSEGV
  151. * Signal actions for these signals are installed by altering the
  152. * XcptAction and SigAction fields for the appropriate entry in the
  153. * exception-action table (XcptActTab[]).
  154. *
  155. * 2. Signals corresponding to ^C and ^Break. These are:
  156. * SIGINT
  157. * SIGBREAK
  158. * Signal actions for these signals are installed by altering the
  159. * _ctrlc_action and _ctrlbreak_action variables.
  160. *
  161. * 3. Signals which are implemented only in the runtime. That is, they
  162. * occur only as the result of a call to raise().
  163. * SIGABRT
  164. * SIGTERM
  165. *
  166. *
  167. *Entry:
  168. * int signum signal type. recognized signal types are:
  169. *
  170. * SIGABRT (ANSI)
  171. * SIGBREAK
  172. * SIGFPE (ANSI)
  173. * SIGILL (ANSI)
  174. * SIGINT (ANSI)
  175. * SIGSEGV (ANSI)
  176. * SIGTERM (ANSI)
  177. *
  178. * _PHNDLR sigact signal handling function or action code. the action
  179. * codes are:
  180. *
  181. * SIG_DFL - take the default action, whatever that may
  182. * be, upon receipt of this type type of signal.
  183. *
  184. * SIG_DIE - *** ILLEGAL ***
  185. * special code used in the XcptAction field of an
  186. * XcptActTab[] entry to indicate that the runtime is
  187. * to terminate the process upon receipt of the exception.
  188. * not accepted as a value for sigact.
  189. *
  190. * SIG_IGN - ignore this type of signal
  191. *
  192. * [function address] - transfer control to this address
  193. * when a signal of this type occurs.
  194. *
  195. *Exit:
  196. * Good return:
  197. * Signal returns the previous value of the signal handling function
  198. * (e.g., SIG_DFL, SIG_IGN, etc., or [function address]). This value is
  199. * returned in DX:AX.
  200. *
  201. * Error return:
  202. * Signal returns -1 and errno is set to EINVAL. The error return is
  203. * generally taken if the user submits bogus input values.
  204. *
  205. *Exceptions:
  206. * None.
  207. *
  208. *******************************************************************************/
  209. _PHNDLR __cdecl signal(
  210. int signum,
  211. _PHNDLR sigact
  212. )
  213. {
  214. struct _XCPT_ACTION *pxcptact;
  215. _PHNDLR oldsigact;
  216. #ifdef _MT
  217. _ptiddata ptd;
  218. #endif
  219. /*
  220. * Check for values of sigact supported on other platforms but not
  221. * on this one. Also, make sure sigact is not SIG_DIE
  222. */
  223. if ( (sigact == SIG_ACK) || (sigact == SIG_SGE) )
  224. goto sigreterror;
  225. /*
  226. * Take care of all signals which do not correspond to exceptions
  227. * in the host OS. Those are:
  228. *
  229. * SIGINT
  230. * SIGBREAK
  231. * SIGABRT
  232. * SIGTERM
  233. *
  234. */
  235. if ( (signum == SIGINT) || (signum == SIGBREAK) || (signum == SIGABRT)
  236. || (signum == SIGTERM) ) {
  237. #ifdef _MT
  238. _mlock( _SIGNAL_LOCK );
  239. __try {
  240. #endif
  241. /*
  242. * if SIGINT or SIGBREAK, make sure the handler is installed
  243. * to capture ^C and ^Break events.
  244. */
  245. if ( ((signum == SIGINT) || (signum == SIGBREAK)) &&
  246. !ConsoleCtrlHandler_Installed )
  247. if ( SetConsoleCtrlHandler(ctrlevent_capture, TRUE)
  248. == TRUE )
  249. ConsoleCtrlHandler_Installed = TRUE;
  250. else {
  251. _doserrno = GetLastError();
  252. _munlock(_SIGNAL_LOCK);
  253. goto sigreterror;
  254. }
  255. switch (signum) {
  256. case SIGINT:
  257. oldsigact = ctrlc_action;
  258. ctrlc_action = sigact;
  259. break;
  260. case SIGBREAK:
  261. oldsigact = ctrlbreak_action;
  262. ctrlbreak_action = sigact;
  263. break;
  264. case SIGABRT:
  265. oldsigact = abort_action;
  266. abort_action = sigact;
  267. break;
  268. case SIGTERM:
  269. oldsigact = term_action;
  270. term_action = sigact;
  271. break;
  272. }
  273. #ifdef _MT
  274. }
  275. __finally {
  276. _munlock( _SIGNAL_LOCK );
  277. }
  278. #endif
  279. goto sigretok;
  280. }
  281. /*
  282. * If we reach here, signum is supposed to be one the signals which
  283. * correspond to exceptions in the host OS. Those are:
  284. *
  285. * SIGFPE
  286. * SIGILL
  287. * SIGSEGV
  288. */
  289. /*
  290. * Make sure signum is one of the remaining supported signals.
  291. */
  292. if ( (signum != SIGFPE) && (signum != SIGILL) && (signum != SIGSEGV) )
  293. goto sigreterror;
  294. #ifdef _MT
  295. /*
  296. * Fetch the tid data table entry for this thread
  297. */
  298. ptd = _getptd();
  299. /*
  300. * Check that there a per-thread instance of the exception-action
  301. * table for this thread. if there isn't, create one.
  302. */
  303. if ( ptd->_pxcptacttab == _XcptActTab )
  304. /*
  305. * allocate space for an exception-action table
  306. */
  307. if ( (ptd->_pxcptacttab = _malloc_crt(_XcptActTabSize)) != NULL )
  308. /*
  309. * initialize the table by copying over the contents
  310. * of _XcptActTab[]
  311. */
  312. (void) memcpy(ptd->_pxcptacttab, _XcptActTab,
  313. _XcptActTabSize);
  314. else
  315. /*
  316. * cannot create exception-action table, return
  317. * error to caller
  318. */
  319. goto sigreterror;
  320. #endif /* _MT */
  321. /*
  322. * look up the proper entry in the exception-action table. note that
  323. * if several exceptions are mapped to the same signal, this returns
  324. * the pointer to first such entry in the exception action table. it
  325. * is assumed that the other entries immediately follow this one.
  326. */
  327. #ifdef _MT
  328. if ( (pxcptact = siglookup(signum, ptd->_pxcptacttab)) == NULL )
  329. #else /* not _MT */
  330. if ( (pxcptact = siglookup(signum)) == NULL )
  331. #endif /* _MT */
  332. goto sigreterror;
  333. /*
  334. * SIGSEGV, SIGILL and SIGFPE all have more than one exception mapped
  335. * to them. the code below depends on the exceptions corresponding to
  336. * the same signal being grouped together in the exception-action
  337. * table.
  338. */
  339. /*
  340. * store old signal action code for return value
  341. */
  342. oldsigact = pxcptact->XcptAction;
  343. /*
  344. * loop through all entries corresponding to the
  345. * given signal and update the SigAction and XcptAction
  346. * fields as appropriate
  347. */
  348. while ( pxcptact->SigNum == signum ) {
  349. /*
  350. * take care of the SIG_IGN and SIG_DFL action
  351. * codes
  352. */
  353. pxcptact->XcptAction = sigact;
  354. /*
  355. * make sure we don't run off the end of the table
  356. */
  357. #ifdef _MT
  358. if ( ++pxcptact >= ((struct _XCPT_ACTION *)(ptd->_pxcptacttab)
  359. + _XcptActTabCount) )
  360. #else /* not _MT */
  361. if ( ++pxcptact >= (_XcptActTab + _XcptActTabCount) )
  362. #endif /* _MT */
  363. break;
  364. }
  365. sigretok:
  366. return(oldsigact);
  367. sigreterror:
  368. errno = EINVAL;
  369. return(SIG_ERR);
  370. }
  371. /***
  372. *int raise(signum) - Raise a signal
  373. *
  374. *Purpose:
  375. * This routine raises a signal (i.e., performs the action currently
  376. * defined for this signal). The action associated with the signal is
  377. * evoked directly without going through intermediate dispatching or
  378. * handling.
  379. *
  380. *Entry:
  381. * int signum - signal type (e.g., SIGINT)
  382. *
  383. *Exit:
  384. * returns 0 on good return, -1 on bad return.
  385. *
  386. *Exceptions:
  387. * May not return. Raise has no control over the action
  388. * routines defined for the various signals. Those routines may
  389. * abort, terminate, etc. In particular, the default actions for
  390. * certain signals will terminate the program.
  391. *
  392. *******************************************************************************/
  393. int __cdecl raise (
  394. int signum
  395. )
  396. {
  397. _PHNDLR sigact;
  398. _PHNDLR *psigact;
  399. PEXCEPTION_POINTERS oldpxcptinfoptrs;
  400. int oldfpecode;
  401. int indx;
  402. #ifdef _MT
  403. int siglock = 0;
  404. _ptiddata ptd;
  405. #endif
  406. switch (signum) {
  407. case SIGINT:
  408. sigact = *(psigact = &ctrlc_action);
  409. #ifdef _MT
  410. siglock++;
  411. #endif
  412. break;
  413. case SIGBREAK:
  414. sigact = *(psigact = &ctrlbreak_action);
  415. #ifdef _MT
  416. siglock++;
  417. #endif
  418. break;
  419. case SIGABRT:
  420. sigact = *(psigact = &abort_action);
  421. #ifdef _MT
  422. siglock++;
  423. #endif
  424. break;
  425. case SIGTERM:
  426. sigact = *(psigact = &term_action);
  427. #ifdef _MT
  428. siglock++;
  429. #endif
  430. break;
  431. case SIGFPE:
  432. case SIGILL:
  433. case SIGSEGV:
  434. #ifdef _MT
  435. ptd = _getptd();
  436. sigact = *(psigact = &(siglookup( signum,
  437. ptd->_pxcptacttab )->XcptAction));
  438. #else
  439. sigact = *(psigact = &(siglookup( signum )->
  440. XcptAction));
  441. #endif
  442. break;
  443. default:
  444. /*
  445. * unsupported signal, return an error
  446. */
  447. return (-1);
  448. }
  449. /*
  450. * If the current action is SIG_IGN, just return
  451. */
  452. if ( sigact == SIG_IGN )
  453. return(0);
  454. /*
  455. * If the current action is SIG_DFL, take the default action
  456. */
  457. if ( sigact == SIG_DFL ) {
  458. /*
  459. * The current default action for all of the supported
  460. * signals is to terminate with an exit code of 3.
  461. */
  462. _exit(3);
  463. }
  464. #ifdef _MT
  465. /*
  466. * if signum is one of the 'process-wide' signals (i.e., SIGINT,
  467. * SIGBREAK, SIGABRT or SIGTERM), assert _SIGNAL_LOCK.
  468. */
  469. if ( siglock )
  470. _mlock(_SIGNAL_LOCK);
  471. __try {
  472. #endif
  473. /*
  474. * From here on, sigact is assumed to be a pointer to a user-supplied
  475. * handler.
  476. */
  477. /*
  478. * For signals which correspond to exceptions, set the pointer
  479. * to the EXCEPTION_POINTERS structure to NULL
  480. */
  481. if ( (signum == SIGFPE) || (signum == SIGSEGV) ||
  482. (signum == SIGILL) ) {
  483. #ifdef _MT
  484. oldpxcptinfoptrs = ptd->_tpxcptinfoptrs;
  485. ptd->_tpxcptinfoptrs = NULL;
  486. #else
  487. oldpxcptinfoptrs = _pxcptinfoptrs;
  488. _pxcptinfoptrs = NULL;
  489. #endif
  490. /*
  491. * If signum is SIGFPE, also set _fpecode to
  492. * _FPE_EXPLICITGEN
  493. */
  494. if ( signum == SIGFPE ) {
  495. #ifdef _MT
  496. oldfpecode = ptd->_tfpecode;
  497. ptd->_tfpecode = _FPE_EXPLICITGEN;
  498. #else
  499. oldfpecode = _fpecode;
  500. _fpecode = _FPE_EXPLICITGEN;
  501. #endif
  502. }
  503. }
  504. /*
  505. * Reset the action to SIG_DFL and call the user specified handler
  506. * routine.
  507. */
  508. if ( signum == SIGFPE )
  509. /*
  510. * for SIGFPE, must reset the action for all of the floating
  511. * point exceptions
  512. */
  513. for ( indx = _First_FPE_Indx ;
  514. indx < _First_FPE_Indx + _Num_FPE ;
  515. indx++ )
  516. {
  517. #ifdef _MT
  518. ( (struct _XCPT_ACTION *)(ptd->_pxcptacttab) +
  519. indx )->XcptAction = SIG_DFL;
  520. #else
  521. _XcptActTab[indx].XcptAction = SIG_DFL;
  522. #endif
  523. }
  524. else
  525. *psigact = SIG_DFL;
  526. #ifdef _MT
  527. }
  528. __finally {
  529. if ( siglock )
  530. _munlock(_SIGNAL_LOCK);
  531. }
  532. #endif
  533. if ( signum == SIGFPE )
  534. /*
  535. * Special code to support old SIGFPE handlers which
  536. * expect the value of _fpecode as the second argument.
  537. */
  538. #ifdef _MT
  539. (*(void (__cdecl *)(int,int))sigact)(SIGFPE,
  540. ptd->_tfpecode);
  541. #else
  542. (*(void (__cdecl *)(int,int))sigact)(SIGFPE, _fpecode);
  543. #endif
  544. else
  545. (*sigact)(signum);
  546. /*
  547. * For signals which correspond to exceptions, restore the pointer
  548. * to the EXCEPTION_POINTERS structure.
  549. */
  550. if ( (signum == SIGFPE) || (signum == SIGSEGV) ||
  551. (signum == SIGILL) ) {
  552. #ifdef _MT
  553. ptd->_tpxcptinfoptrs = oldpxcptinfoptrs;
  554. #else
  555. _pxcptinfoptrs = oldpxcptinfoptrs;
  556. #endif
  557. /*
  558. * If signum is SIGFPE, also restore _fpecode
  559. */
  560. if ( signum == SIGFPE )
  561. #ifdef _MT
  562. ptd->_tfpecode = oldfpecode;
  563. #else
  564. _fpecode = oldfpecode;
  565. #endif
  566. }
  567. return(0);
  568. }
  569. /***
  570. *struct _XCPT_ACTION *siglookup(int signum) - look up exception-action table
  571. * entry for signal.
  572. *
  573. *Purpose:
  574. * Find the first entry int _XcptActTab[] whose SigNum field is signum.
  575. *
  576. *Entry:
  577. * int signum - C signal type (e.g., SIGINT)
  578. *
  579. *Exit:
  580. * If successful, pointer to the table entry. If no such entry, NULL is
  581. * returned.
  582. *
  583. *Exceptions:
  584. *
  585. *******************************************************************************/
  586. #ifdef _MT
  587. static struct _XCPT_ACTION * __cdecl siglookup (
  588. int signum,
  589. struct _XCPT_ACTION *pxcptacttab
  590. )
  591. {
  592. struct _XCPT_ACTION *pxcptact = pxcptacttab;
  593. #else /* not _MT */
  594. static struct _XCPT_ACTION * __cdecl siglookup(int signum)
  595. {
  596. struct _XCPT_ACTION *pxcptact = _XcptActTab;
  597. #endif /* _MT */
  598. /*
  599. * walk thru the _xcptactab table looking for the proper entry. note
  600. * that in the case where more than one exception corresponds to the
  601. * same signal, the first such instance in the table is the one
  602. * returned.
  603. */
  604. #ifdef _MT
  605. while ( (pxcptact->SigNum != signum) &&
  606. (++pxcptact < pxcptacttab + _XcptActTabCount) ) ;
  607. #else /* not _MT */
  608. while ( (pxcptact->SigNum != signum) &&
  609. (++pxcptact < _XcptActTab + _XcptActTabCount) ) ;
  610. #endif /* _MT */
  611. #ifdef _MT
  612. if ( (pxcptact < (pxcptacttab + _XcptActTabCount)) &&
  613. #else /* not _MT */
  614. if ( (pxcptact < (_XcptActTab + _XcptActTabCount)) &&
  615. #endif /* _MT */
  616. (pxcptact->SigNum == signum) )
  617. /*
  618. * found a table entry corresponding to the signal
  619. */
  620. return(pxcptact);
  621. else
  622. /*
  623. * found no table entry corresponding to the signal
  624. */
  625. return(NULL);
  626. }
  627. #ifdef _MT
  628. /***
  629. *int *__fpecode(void) - return pointer to _fpecode field of the tidtable entry
  630. * for the current thread
  631. *
  632. *Purpose:
  633. *
  634. *Entry:
  635. *
  636. *Exit:
  637. *
  638. *Exceptions:
  639. *
  640. *******************************************************************************/
  641. int * __cdecl __fpecode (
  642. void
  643. )
  644. {
  645. return( &(_getptd()->_tfpecode) );
  646. }
  647. /***
  648. *void **__pxcptinfoptrs(void) - return pointer to _pxcptinfoptrs field of the
  649. * tidtable entry for the current thread
  650. *
  651. *Purpose:
  652. *
  653. *Entry:
  654. *
  655. *Exit:
  656. *
  657. *Exceptions:
  658. *
  659. *******************************************************************************/
  660. void ** __cdecl __pxcptinfoptrs (
  661. void
  662. )
  663. {
  664. return( &(_getptd()->_tpxcptinfoptrs) );
  665. }
  666. #endif
  667. #endif /* _POSIX_ */