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

  1. /***
  2. *onexit.c - save function for execution on exit
  3. *
  4. *       Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *       defines _onexit(), atexit() - save function for execution at exit
  8. *
  9. *       In order to save space, the table is allocated via malloc/realloc,
  10. *       and only consumes as much space as needed.  __onexittable is
  11. *       set to point to the table if onexit() is ever called.
  12. *
  13. *******************************************************************************/
  14.  
  15. #ifdef _WIN32
  16.  
  17. #include <cruntime.h>
  18. #include <mtdll.h>
  19. #include <stdlib.h>
  20. #include <internal.h>
  21. #include <malloc.h>
  22. #include <rterr.h>
  23. #include <windows.h>
  24. #include <dbgint.h>
  25.  
  26.  
  27. void __cdecl __onexitinit(void);
  28.  
  29. #ifdef _MSC_VER
  30.  
  31. #pragma data_seg(".CRT$XIC")
  32. static _PVFV pinit = __onexitinit;
  33.  
  34. #pragma data_seg()
  35.  
  36. #endif  /* _MSC_VER */
  37.  
  38. /*
  39.  * Define pointers to beginning and end of the table of function pointers
  40.  * manipulated by _onexit()/atexit().
  41.  */
  42. extern _PVFV *__onexitbegin;
  43. extern _PVFV *__onexitend;
  44.  
  45. /*
  46.  * Define increment (in entries) for growing the _onexit/atexit table
  47.  */
  48. #define ONEXITTBLINCR   4
  49.  
  50.  
  51. /***
  52. *_onexit(func), atexit(func) - add function to be executed upon exit
  53. *
  54. *Purpose:
  55. *       The _onexit/atexit functions are passed a pointer to a function
  56. *       to be called when the program terminate normally.  Successive
  57. *       calls create a register of functions that are executed last in,
  58. *       first out.
  59. *
  60. *Entry:
  61. *       void (*func)() - pointer to function to be executed upon exit
  62. *
  63. *Exit:
  64. *       onexit:
  65. *           Success - return pointer to user's function.
  66. *           Error - return NULL pointer.
  67. *       atexit:
  68. *           Success - return 0.
  69. *           Error - return non-zero value.
  70. *
  71. *Notes:
  72. *       This routine depends on the behavior of _initterm() in CRT0DAT.C.
  73. *       Specifically, _initterm() must not skip the address pointed to by
  74. *       its first parameter, and must also stop before the address pointed
  75. *       to by its second parameter.  This is because _onexitbegin will point
  76. *       to a valid address, and _onexitend will point at an invalid address.
  77. *
  78. *Exceptions:
  79. *
  80. *******************************************************************************/
  81.  
  82.  
  83. _onexit_t __cdecl _onexit (
  84.         _onexit_t func
  85.         )
  86. {
  87.         _PVFV   *p;
  88.  
  89. #ifdef _MT
  90.         _lockexit();            /* lock the exit code */
  91. #endif  /* _MT */
  92.  
  93.         /*
  94.          * First, make sure the table has room for a new entry
  95.          */
  96.         if ( _msize_crt(__onexitbegin)
  97.                 < ((unsigned)((char *)__onexitend -
  98.             (char *)__onexitbegin) + sizeof(_PVFV)) ) {
  99.             /*
  100.              * not enough room, try to grow the table
  101.              */
  102.             if ( (p = (_PVFV *) _realloc_crt(__onexitbegin,
  103.                 _msize_crt(__onexitbegin) +
  104.                 ONEXITTBLINCR * sizeof(_PVFV))) == NULL )
  105.             {
  106.                 /*
  107.                  * didn't work. don't do anything rash, just fail
  108.                  */
  109. #ifdef _MT
  110.                 _unlockexit();
  111. #endif  /* _MT */
  112.  
  113.                 return NULL;
  114.             }
  115.  
  116.             /*
  117.              * update __onexitend and __onexitbegin
  118.              */
  119.             __onexitend = p + (__onexitend - __onexitbegin);
  120.             __onexitbegin = p;
  121.         }
  122.  
  123.         /*
  124.          * Put the new entry into the table and update the end-of-table
  125.          * pointer.
  126.          */
  127.          *(__onexitend++) = (_PVFV)func;
  128.  
  129. #ifdef _MT
  130.         _unlockexit();
  131. #endif  /* _MT */
  132.  
  133.         return func;
  134.  
  135. }
  136.  
  137. int __cdecl atexit (
  138.         _PVFV func
  139.         )
  140. {
  141.         return (_onexit((_onexit_t)func) == NULL) ? -1 : 0;
  142. }
  143.  
  144.  
  145. /***
  146. * void __onexitinit(void) - initialization routine for the function table
  147. *       used by _onexit() and atexit().
  148. *
  149. *Purpose:
  150. *       Allocate the table with room for 32 entries (minimum required by
  151. *       ANSI). Also, initialize the pointers to the beginning and end of
  152. *       the table.
  153. *
  154. *Entry:
  155. *       None.
  156. *
  157. *Exit:
  158. *       No return value. A fatal runtime error is generated if the table
  159. *       cannot be allocated.
  160. *
  161. *Notes:
  162. *       This routine depends on the behavior of doexit() in CRT0DAT.C.
  163. *       Specifically, doexit() must not skip the address pointed to by
  164. *       __onexitbegin, and it must also stop before the address pointed
  165. *       to by __onexitend.  This is because _onexitbegin will point
  166. *       to a valid address, and _onexitend will point at an invalid address.
  167. *
  168. *       Since the table of onexit routines is built in forward order, it
  169. *       must be traversed by doexit() in CRT0DAT.C in reverse order.  This
  170. *       is because these routines must be called in last-in, first-out order.
  171. *
  172. *       If __onexitbegin == __onexitend, then the onexit table is empty!
  173. *
  174. *Exceptions:
  175. *
  176. *******************************************************************************/
  177.  
  178. void __cdecl __onexitinit (
  179.         void
  180.         )
  181. {
  182.         if ( (__onexitbegin = (_PVFV *)_malloc_crt(32 * sizeof(_PVFV))) == NULL )
  183.             /*
  184.              * cannot allocate minimal required size. generate
  185.              * fatal runtime error.
  186.              */
  187.             _amsg_exit(_RT_ONEXIT);
  188.  
  189.         *(__onexitbegin) = (_PVFV) NULL;
  190.         __onexitend = __onexitbegin;
  191. }
  192.  
  193.  
  194. #ifdef CRTDLL
  195.  
  196. /***
  197. *__dllonexit(func, pbegin, pend) - add function to be executed upon DLL detach
  198. *
  199. *Purpose:
  200. *       The _onexit/atexit functions in a DLL linked with MSVCRT.LIB
  201. *       must maintain their own atexit/_onexit list.  This routine is
  202. *       the worker that gets called by such DLLs.  It is analogous to
  203. *       the regular _onexit above except that the __onexitbegin and
  204. *       __onexitend variables are not global variables visible to this
  205. *       routine but rather must be passed as parameters.
  206. *
  207. *Entry:
  208. *       void (*func)() - pointer to function to be executed upon exit
  209. *       void (***pbegin)() - pointer to variable pointing to the beginning
  210. *                   of list of functions to execute on detach
  211. *       void (***pend)() - pointer to variable pointing to the end of list
  212. *                   of functions to execute on detach
  213. *
  214. *Exit:
  215. *       Success - return pointer to user's function.
  216. *       Error - return NULL pointer.
  217. *
  218. *Notes:
  219. *       This routine depends on the behavior of _initterm() in CRT0DAT.C.
  220. *       Specifically, _initterm() must not skip the address pointed to by
  221. *       its first parameter, and must also stop before the address pointed
  222. *       to by its second parameter.  This is because *pbegin will point
  223. *       to a valid address, and *pend will point at an invalid address.
  224. *
  225. *Exceptions:
  226. *
  227. *******************************************************************************/
  228.  
  229. _onexit_t __cdecl __dllonexit (
  230.         _onexit_t func,
  231.         _PVFV ** pbegin,
  232.         _PVFV ** pend
  233.         )
  234. {
  235.         _PVFV   *p;
  236.         unsigned oldsize;
  237.  
  238. #ifdef _MT
  239.         _lockexit();            /* lock the exit code */
  240. #endif  /* _MT */
  241.  
  242.         /*
  243.          * First, make sure the table has room for a new entry
  244.          */
  245.         if ( (oldsize = _msize_crt( *pbegin )) <= (unsigned)((char *)(*pend) -
  246.             (char *)(*pbegin)) ) {
  247.             /*
  248.              * not enough room, try to grow the table
  249.              */
  250.             if ( (p = (_PVFV *) _realloc_crt((*pbegin), oldsize +
  251.                 ONEXITTBLINCR * sizeof(_PVFV))) == NULL )
  252.             {
  253.                 /*
  254.                  * didn't work. don't do anything rash, just fail
  255.                  */
  256. #ifdef _MT
  257.                 _unlockexit();
  258. #endif  /* _MT */
  259.  
  260.                 return NULL;
  261.             }
  262.  
  263.             /*
  264.              * update (*pend) and (*pbegin)
  265.              */
  266.             (*pend) = p + ((*pend) - (*pbegin));
  267.             (*pbegin) = p;
  268.         }
  269.  
  270.         /*
  271.          * Put the new entry into the table and update the end-of-table
  272.          * pointer.
  273.          */
  274.          *((*pend)++) = (_PVFV)func;
  275.  
  276. #ifdef _MT
  277.         _unlockexit();
  278. #endif  /* _MT */
  279.  
  280.         return func;
  281.  
  282. }
  283.  
  284. #endif  /* CRTDLL */
  285.  
  286. #else  /* _WIN32 */
  287.  
  288. #include <cruntime.h>
  289. #include <mtdll.h>
  290. #include <stdlib.h>
  291. #include <internal.h>
  292. #include <fltintrn.h>            //PFV definition
  293. #include <malloc.h>
  294. #include <rterr.h>
  295. #include <dbgint.h>
  296.  
  297. /*
  298.  * Define pointers to beginning and end of the table of function pointers
  299.  * manipulated by _onexit()/atexit().
  300.  */
  301. extern PFV *__onexitbegin;
  302. extern PFV *__onexitend;
  303.  
  304. /*
  305.  * Define increment (in entries) for growing the _onexit/atexit table
  306.  */
  307. #define ONEXITTBLINCR   4
  308.  
  309.  
  310. /***
  311. *_onexit(func), atexit(func) - add function to be executed upon exit
  312. *
  313. *Purpose:
  314. *       The _onexit/atexit functions are passed a pointer to a function
  315. *       to be called when the program terminate normally.  Successive
  316. *       calls create a register of functions that are executed last in,
  317. *       first out.
  318. *
  319. *Entry:
  320. *       void (*func)() - pointer to function to be executed upon exit
  321. *
  322. *Exit:
  323. *       onexit:
  324. *               Success - return pointer to user's function.
  325. *               Error - return NULL pointer.
  326. *       atexit:
  327. *               Success - return 0.
  328. *               Error - return non-zero value.
  329. *
  330. *Notes:
  331. *       This routine depends on the behavior of _initterm() in CRT0DAT.C.
  332. *       Specifically, _initterm() must not skip the address pointed to by
  333. *       its first parameter, and must also stop before the address pointed
  334. *       to by its second parameter.  This is because _onexitbegin will point
  335. *       to a valid address, and _onexitend will point at an invalid address.
  336. *
  337. *Exceptions:
  338. *
  339. *******************************************************************************/
  340.  
  341.  
  342. #ifndef CRTDLL
  343. _onexit_t _cdecl _onexit (
  344. #else  /* CRTDLL */
  345. _onexit_t _cdecl __onexit (
  346. #endif  /* CRTDLL */
  347.         _onexit_t func
  348.         )
  349.  
  350. {
  351.         PFV     *p;
  352.  
  353.         /*
  354.          * First, make sure the table has room for a new entry
  355.          */
  356.         if ( _msize_crt(__onexitbegin) <= (unsigned)((char *)__onexitend -
  357.             (char *)__onexitbegin) ) {
  358.             /*
  359.              * not enough room, try to grow the table
  360.              */
  361.             if ( (p = (PFV *) _realloc_crt(__onexitbegin, _msize(__onexitbegin) +
  362.                 ONEXITTBLINCR * sizeof(PFV))) == NULL ) {
  363.                 /*
  364.                  * didn't work. don't do anything rash, just fail
  365.                  */
  366.                 return NULL;
  367.             }
  368.  
  369.             /*
  370.              * update __onexitend and __onexitbegin
  371.              */
  372.             __onexitend = p + (__onexitend - __onexitbegin);
  373.             __onexitbegin = p;
  374.         }
  375.  
  376.         /* push the table down one entry and insert new one at top since we
  377.             need LIFO order */
  378.  
  379.         for (p = __onexitend++; p > __onexitbegin; p--) {
  380.             *p = *(p-1);
  381.         }
  382.         *__onexitbegin = (PFV)func;
  383.         return func;
  384. }
  385.  
  386.  
  387. #ifndef CRTDLL
  388.  
  389. int _CALLTYPE1 atexit (
  390.         PFV func
  391.         )
  392. {
  393.         return (_onexit((_onexit_t)func) == NULL) ? -1 : 0;
  394. }
  395.  
  396. #endif  /* CRTDLL */
  397.  
  398. /***
  399. * void _onexitinit(void) - initialization routine for the function table
  400. *       used by _onexit() and _atexit().
  401. *
  402. *Purpose:
  403. *       Allocate the table with room for 32 entries (minimum required by
  404. *       ANSI). Also, initialize the pointers to the beginning and end of
  405. *       the table.
  406. *
  407. *Entry:
  408. *       None.
  409. *
  410. *Exit:
  411. *       No return value. A fatal runtime error is generated if the table
  412. *       cannot be allocated.
  413. *
  414. *Notes:
  415. *       This routine depends on the behavior of _initterm() in CRT0DAT.C.
  416. *       Specifically, _initterm() must not skip the address pointed to by
  417. *       its first parameter, and must also stop before the address pointed
  418. *       to by its second parameter.  This is because _onexitbegin will point
  419. *       to a valid address, and _onexitend will point at an invalid address.
  420. *
  421. *Exceptions:
  422. *
  423. *******************************************************************************/
  424.  
  425.  
  426. /*      define the entry in initializer table */
  427.  
  428.  
  429. #pragma data_seg(".CRT$XIC")
  430.  
  431. static PFV __ponexitinit = _onexitinit;
  432.  
  433. #pragma data_seg()
  434.  
  435. void _CALLTYPE1 _onexitinit (
  436.         void
  437.         )
  438. {
  439.         if ( (__onexitbegin = (PFV *)_malloc_crt(32 * sizeof(PFV))) == NULL )
  440.             /*
  441.              * cannot allocate minimal required size. generate
  442.              * fatal runtime error.
  443.              */
  444.             _amsg_exit(_RT_ONEXIT);
  445.  
  446.         *(__onexitbegin) = NULL;
  447.         __onexitend = __onexitbegin;
  448. }
  449.  
  450. #ifdef CRTDLL
  451.  
  452. /***
  453. *__dllonexit(func, pbegin, pend) - add function to be executed upon DLL detach
  454. *
  455. *Purpose:
  456. *       The _onexit/atexit functions in a DLL linked with MSVCRT.LIB
  457. *       must maintain their own atexit/_onexit list.  This routine is
  458. *       the worker that gets called by such DLLs.  It is analogous to
  459. *       the regular _onexit above except that the __onexitbegin and
  460. *       __onexitend variables are not global variables visible to this
  461. *       routine but rather must be passed as parameters.
  462. *
  463. *Entry:
  464. *       void (*func)() - pointer to function to be executed upon exit
  465. *       void (***pbegin)() - pointer to variable pointing to the beginning
  466. *                   of list of functions to execute on detach
  467. *       void (***pend)() - pointer to variable pointing to the end of list
  468. *                   of functions to execute on detach
  469. *
  470. *Exit:
  471. *       Success - return pointer to user's function.
  472. *       Error - return NULL pointer.
  473. *
  474. *Notes:
  475. *       This routine depends on the behavior of _initterm() in CRT0DAT.C.
  476. *       Specifically, _initterm() must not skip the address pointed to by
  477. *       its first parameter, and must also stop before the address pointed
  478. *       to by its second parameter.  This is because *pbegin will point
  479. *       to a valid address, and *pend will point at an invalid address.
  480. *
  481. *Exceptions:
  482. *
  483. *******************************************************************************/
  484.  
  485. _onexit_t _cdecl __dllonexit (
  486.         _onexit_t func,
  487.         PFV ** pbegin,
  488.         PFV ** pend
  489.         )
  490. {
  491.         PFV   *p;
  492.         unsigned oldsize;
  493.  
  494.         /*
  495.          * First, make sure the table has room for a new entry
  496.          */
  497.         if ( (oldsize = _msize_crt( *pbegin )) <= (unsigned)((char *)(*pend) -
  498.             (char *)(*pbegin)) ) {
  499.             /*
  500.              * not enough room, try to grow the table
  501.              */
  502.             if ( (p = (PFV *) _realloc_crt((*pbegin), oldsize +
  503.                 ONEXITTBLINCR * sizeof(PFV))) == NULL )
  504.             {
  505.                 /*
  506.                  * didn't work. don't do anything rash, just fail
  507.                  */
  508.  
  509.                 return NULL;
  510.             }
  511.  
  512.             /*
  513.              * update (*pend) and (*pbegin)
  514.              */
  515.             (*pend) = p + ((*pend) - (*pbegin));
  516.             (*pbegin) = p;
  517.         }
  518.  
  519.         /*
  520.          * Put the new entry into the table and update the end-of-table
  521.          * pointer.
  522.          */
  523.  
  524.         *((*pend)++) = (PFV)func;
  525.         return func;
  526. }
  527.  
  528. #endif  /* CRTDLL */
  529. #endif  /* _WIN32 */
  530.