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.

369 lines
12 KiB

  1. /***
  2. *onexit.c - save function for execution on exit
  3. *
  4. * Copyright (c) 1989-2001, 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. *Revision History:
  14. * 06-30-89 PHG module created, based on asm version
  15. * 03-15-90 GJF Replace _cdecl with _CALLTYPE1, added #include
  16. * <cruntime.h> and fixed the copyright. Also,
  17. * cleaned up the formatting a bit.
  18. * 05-21-90 GJF Fixed compiler warning.
  19. * 10-04-90 GJF New-style function declarators.
  20. * 12-28-90 SRW Added casts of func for Mips C Compiler
  21. * 01-21-91 GJF ANSI naming.
  22. * 09-09-91 GJF Revised for C++ needs.
  23. * 03-20-92 SKS Revamped for new initialization model
  24. * 04-01-92 XY add init code reference for MAC version
  25. * 04-23-92 DJM POSIX support.
  26. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  27. * 05-24-93 SKS Add __dllonexit for DLLs using MSVCRT10.DLL
  28. * 09-15-93 GJF Merged NT SDK and Cuda versions. This amounted to
  29. * resurrecting and cleaning up the Posix verion (which
  30. * may prove obsolete after later review).
  31. * 10-28-93 GJF Define entry for initialization section (used to be
  32. * in i386\cinitone.asm).
  33. * 04-12-94 GJF Made declarations of _onexitbegin and _onexitend
  34. * conditional on ndef DLL_FOR_WIN32S.
  35. * 05-19-94 GJF For DLL_FOR_WIN32S, changed the reallocation of the
  36. * onexit/atexit table in __dllonexit to use malloc and
  37. * __mark_block_as_free, instead of realloc.
  38. * 06-06-94 GJF Replaced 5-19-94 code with use of GlobalAlloc and
  39. * GlobalFree.
  40. * 07-18-94 GJF Must specify GMEM_SHARE in GlobalAlloc.
  41. * 08-22-94 GJF Fixed table size test to remove implicit assumption
  42. * that the heap allocation granularity is at least
  43. * sizeof(_PVFV). This removes a barrier to working with
  44. * a user-supplied, or third party, heap manager.
  45. * 01-10-95 CFW Debug CRT allocs.
  46. * 02-02-95 BWT Update POSIX support (it's the same as Win32 now)
  47. * 02-14-95 CFW Debug CRT allocs.
  48. * 02-16-95 JWM Spliced _WIN32 & Mac versions.
  49. * 03-29-95 BWT Add _msize prototype to fix POSIX build.
  50. * 08-01-96 RDK Changed initialization pointer data type, changed
  51. * _onexit and added _dllonexit to parallel x86
  52. * functionality.
  53. * 03-06-98 GJF Exception-safe locking.
  54. * 12-01-98 GJF Grow the atexit table much more rapidly.
  55. * 12-18-98 GJF Changes for 64-bit size_t.
  56. * 04-28-99 PML Wrap __declspec(allocate()) in _CRTALLOC macro.
  57. * 05-17-99 PML Remove all Macintosh support.
  58. * 03-27-01 PML .CRT$XI routines must now return 0 or _RT_* fatal
  59. * error code (vs7#231220)
  60. *
  61. *******************************************************************************/
  62. #include <sect_attribs.h>
  63. #include <cruntime.h>
  64. #include <mtdll.h>
  65. #include <stdlib.h>
  66. #include <internal.h>
  67. #include <malloc.h>
  68. #include <rterr.h>
  69. #include <windows.h>
  70. #include <dbgint.h>
  71. #ifdef _POSIX_
  72. _CRTIMP size_t __cdecl _msize(void *);
  73. #endif
  74. int __cdecl __onexitinit(void);
  75. #ifdef _MSC_VER
  76. #pragma data_seg(".CRT$XIC")
  77. _CRTALLOC(".CRT$XIC") static _PIFV pinit = __onexitinit;
  78. #pragma data_seg()
  79. #endif /* _MSC_VER */
  80. /*
  81. * Define pointers to beginning and end of the table of function pointers
  82. * manipulated by _onexit()/atexit().
  83. */
  84. extern _PVFV *__onexitbegin;
  85. extern _PVFV *__onexitend;
  86. /*
  87. * Define increments (in entries) for growing the _onexit/atexit table
  88. */
  89. #define MININCR 4
  90. #define MAXINCR 512
  91. #ifdef _MT
  92. static _onexit_t __cdecl _onexit_lk(_onexit_t);
  93. static _onexit_t __cdecl __dllonexit_lk(_onexit_t, _PVFV **, _PVFV **);
  94. #endif
  95. /***
  96. *_onexit(func), atexit(func) - add function to be executed upon exit
  97. *
  98. *Purpose:
  99. * The _onexit/atexit functions are passed a pointer to a function
  100. * to be called when the program terminate normally. Successive
  101. * calls create a register of functions that are executed last in,
  102. * first out.
  103. *
  104. *Entry:
  105. * void (*func)() - pointer to function to be executed upon exit
  106. *
  107. *Exit:
  108. * onexit:
  109. * Success - return pointer to user's function.
  110. * Error - return NULL pointer.
  111. * atexit:
  112. * Success - return 0.
  113. * Error - return non-zero value.
  114. *
  115. *Notes:
  116. * This routine depends on the behavior of _initterm() in CRT0DAT.C.
  117. * Specifically, _initterm() must not skip the address pointed to by
  118. * its first parameter, and must also stop before the address pointed
  119. * to by its second parameter. This is because _onexitbegin will point
  120. * to a valid address, and _onexitend will point at an invalid address.
  121. *
  122. *Exceptions:
  123. *
  124. *******************************************************************************/
  125. _onexit_t __cdecl _onexit (
  126. _onexit_t func
  127. )
  128. {
  129. #ifdef _MT
  130. _onexit_t retval;
  131. _lockexit();
  132. __try {
  133. retval = _onexit_lk(func);
  134. }
  135. __finally {
  136. _unlockexit();
  137. }
  138. return retval;
  139. }
  140. static _onexit_t __cdecl _onexit_lk (
  141. _onexit_t func
  142. )
  143. {
  144. #endif
  145. _PVFV * p;
  146. size_t oldsize;
  147. /*
  148. * First, make sure the table has room for a new entry
  149. */
  150. if ( (oldsize = _msize_crt(__onexitbegin))
  151. < ((size_t)((char *)__onexitend -
  152. (char *)__onexitbegin) + sizeof(_PVFV)) )
  153. {
  154. /*
  155. * not enough room, try to grow the table. first, try to double it.
  156. */
  157. if ( (p = (_PVFV *)_realloc_crt(__onexitbegin, oldsize +
  158. __min(oldsize, (MAXINCR * sizeof(_PVFV))))) == NULL )
  159. {
  160. /*
  161. * failed, try to grow by MININCR
  162. */
  163. if ( (p = (_PVFV *)_realloc_crt(__onexitbegin, oldsize +
  164. MININCR * sizeof(_PVFV))) == NULL )
  165. /*
  166. * failed again. don't do anything rash, just fail
  167. */
  168. return NULL;
  169. }
  170. /*
  171. * update __onexitend and __onexitbegin
  172. */
  173. __onexitend = p + (__onexitend - __onexitbegin);
  174. __onexitbegin = p;
  175. }
  176. /*
  177. * Put the new entry into the table and update the end-of-table
  178. * pointer.
  179. */
  180. *(__onexitend++) = (_PVFV)func;
  181. return func;
  182. }
  183. int __cdecl atexit (
  184. _PVFV func
  185. )
  186. {
  187. return (_onexit((_onexit_t)func) == NULL) ? -1 : 0;
  188. }
  189. /***
  190. * void __onexitinit(void) - initialization routine for the function table
  191. * used by _onexit() and atexit().
  192. *
  193. *Purpose:
  194. * Allocate the table with room for 32 entries (minimum required by
  195. * ANSI). Also, initialize the pointers to the beginning and end of
  196. * the table.
  197. *
  198. *Entry:
  199. * None.
  200. *
  201. *Exit:
  202. * Returns _RT_ONEXIT if the table cannot be allocated.
  203. *
  204. *Notes:
  205. * This routine depends on the behavior of doexit() in CRT0DAT.C.
  206. * Specifically, doexit() must not skip the address pointed to by
  207. * __onexitbegin, and it must also stop before the address pointed
  208. * to by __onexitend. This is because _onexitbegin will point
  209. * to a valid address, and _onexitend will point at an invalid address.
  210. *
  211. * Since the table of onexit routines is built in forward order, it
  212. * must be traversed by doexit() in CRT0DAT.C in reverse order. This
  213. * is because these routines must be called in last-in, first-out order.
  214. *
  215. * If __onexitbegin == __onexitend, then the onexit table is empty!
  216. *
  217. *Exceptions:
  218. *
  219. *******************************************************************************/
  220. int __cdecl __onexitinit (
  221. void
  222. )
  223. {
  224. if ( (__onexitbegin = (_PVFV *)_malloc_crt(32 * sizeof(_PVFV))) == NULL )
  225. /*
  226. * cannot allocate minimal required size. return
  227. * fatal runtime error.
  228. */
  229. return _RT_ONEXIT;
  230. *(__onexitbegin) = (_PVFV) NULL;
  231. __onexitend = __onexitbegin;
  232. return 0;
  233. }
  234. #ifdef CRTDLL
  235. /***
  236. *__dllonexit(func, pbegin, pend) - add function to be executed upon DLL detach
  237. *
  238. *Purpose:
  239. * The _onexit/atexit functions in a DLL linked with MSVCRT.LIB
  240. * must maintain their own atexit/_onexit list. This routine is
  241. * the worker that gets called by such DLLs. It is analogous to
  242. * the regular _onexit above except that the __onexitbegin and
  243. * __onexitend variables are not global variables visible to this
  244. * routine but rather must be passed as parameters.
  245. *
  246. *Entry:
  247. * void (*func)() - pointer to function to be executed upon exit
  248. * void (***pbegin)() - pointer to variable pointing to the beginning
  249. * of list of functions to execute on detach
  250. * void (***pend)() - pointer to variable pointing to the end of list
  251. * of functions to execute on detach
  252. *
  253. *Exit:
  254. * Success - return pointer to user's function.
  255. * Error - return NULL pointer.
  256. *
  257. *Notes:
  258. * This routine depends on the behavior of _initterm() in CRT0DAT.C.
  259. * Specifically, _initterm() must not skip the address pointed to by
  260. * its first parameter, and must also stop before the address pointed
  261. * to by its second parameter. This is because *pbegin will point
  262. * to a valid address, and *pend will point at an invalid address.
  263. *
  264. *Exceptions:
  265. *
  266. *******************************************************************************/
  267. _onexit_t __cdecl __dllonexit (
  268. _onexit_t func,
  269. _PVFV ** pbegin,
  270. _PVFV ** pend
  271. )
  272. {
  273. #ifdef _MT
  274. _onexit_t retval;
  275. _lockexit();
  276. __try {
  277. retval = __dllonexit_lk(func, pbegin, pend);
  278. }
  279. __finally {
  280. _unlockexit();
  281. }
  282. return retval;
  283. }
  284. static _onexit_t __cdecl __dllonexit_lk (
  285. _onexit_t func,
  286. _PVFV ** pbegin,
  287. _PVFV ** pend
  288. )
  289. {
  290. #endif
  291. _PVFV *p;
  292. size_t oldsize;
  293. /*
  294. * First, make sure the table has room for a new entry
  295. */
  296. if ( (oldsize = _msize_crt(*pbegin)) <= (size_t)((char *)(*pend) -
  297. (char *)(*pbegin)) )
  298. {
  299. /*
  300. * not enough room, try to grow the table
  301. */
  302. if ( (p = (_PVFV *)_realloc_crt((*pbegin), oldsize +
  303. __min(oldsize, MAXINCR * sizeof(_PVFV)))) == NULL )
  304. {
  305. /*
  306. * failed, try to grow by ONEXITTBLINCR
  307. */
  308. if ( (p = (_PVFV *)_realloc_crt((*pbegin), oldsize +
  309. MININCR * sizeof(_PVFV))) == NULL )
  310. /*
  311. * failed again. don't do anything rash, just fail
  312. */
  313. return NULL;
  314. }
  315. /*
  316. * update (*pend) and (*pbegin)
  317. */
  318. (*pend) = p + ((*pend) - (*pbegin));
  319. (*pbegin) = p;
  320. }
  321. /*
  322. * Put the new entry into the table and update the end-of-table
  323. * pointer.
  324. */
  325. *((*pend)++) = (_PVFV)func;
  326. return func;
  327. }
  328. #endif /* CRTDLL */