home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / crt / src / winsig.c < prev    next >
C/C++ Source or Header  |  1998-06-17  |  22KB  |  726 lines

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