Leaked source code of windows server 2003
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.

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