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.

844 lines
26 KiB

  1. /***
  2. *crt0dat.c - 32-bit C run-time initialization/termination routines
  3. *
  4. * Copyright (c) 1986-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * This module contains the routines _cinit, exit, and _exit
  8. * for C run-time startup and termination. _cinit and exit
  9. * are called from the _astart code in crt0.asm.
  10. * This module also defines several data variables used by the
  11. * runtime.
  12. *
  13. * [NOTE: Lock segment definitions are at end of module.]
  14. *
  15. *Revision History:
  16. * 06-28-89 PHG Module created, based on asm version
  17. * 04-09-90 GJF Added #include <cruntime.h>. Made calling type
  18. * explicit (_CALLTYPE1 or _CALLTYPE4). Also, fixed
  19. * the copyright.
  20. * 04-10-90 GJF Fixed compiler warnings (-W3).
  21. * 05-21-90 GJF Added #undef _NFILE_ (temporary hack) and fixed the
  22. * indents.
  23. * 08-31-90 GJF Removed 32 from API names.
  24. * 09-25-90 GJF Merged tree version with local (8-31 and 5-21 changes).
  25. * 10-08-90 GJF New-style function declarators.
  26. * 10-12-90 GJF Removed divide by 0 stuff.
  27. * 10-18-90 GJF Added _pipech[] array.
  28. * 11-05-90 GJF Added _umaskval.
  29. * 12-04-90 GJF Added _osfinfo[] definition for Win32 target. Note that
  30. * the Win32 support is still incomplete!
  31. * 12-04-90 SRW Changed to include <oscalls.h> instead of <doscalls.h>
  32. * 12-04-90 SRW Added _osfile back for win32. Changed _osfinfo from
  33. * an array of structures to an array of 32-bit handles
  34. * (_osfhnd)
  35. * 12-28-90 SRW Added _CRUISER_ conditional around pack pragmas
  36. * 01-29-91 GJF ANSI naming.
  37. * 01-29-91 SRW Added call to GetFileType [_WIN32_]
  38. * 02-18-91 SRW Removed duplicate defintion of _NFILE_ (see mtdll.h)
  39. * 04-04-91 GJF Added definitions for _base[version|major|minor]
  40. * (_WIN32_).
  41. * 04-08-91 GJF Temporary hack for Win32/DOS folks - added HeapDestroy
  42. * call to doexit to tear down the OS heap used by C
  43. * heap.
  44. * 04-09-91 PNT Added _MAC_ conditional
  45. * 04-26-91 SRW Removed level 3 warnings
  46. * 07-16-91 GJF Added fp initialization test-and-call [_WIN32_].
  47. * 07-26-91 GJF Revised initialization and termination stuff. In
  48. * particular, removed need for win32ini.c [_WIN32_].
  49. * 08-07-91 GJF Added init. for FORTRAN runtime, if present [_WIN32_].
  50. * 08-21-91 GJF Test _prmtmp against NULL, not _prmtmp().
  51. * 08-21-91 JCR Added _exitflag, _endstdio, _cpumode, etc.
  52. * 09-09-91 GJF Revised _doinitterm for C++ init. support and to make
  53. * _onexit/atexit compatible with C++ needs.
  54. * 09-16-91 GJF Must test __onexitend before calling _doinitterm.
  55. * 10-29-91 GJF Force in floating point initialization for MIPS
  56. * compiler [_WIN32_].
  57. * 11-13-91 GJF FORTRAN needs _onexit/atexit init. before call thru
  58. * _pFFinit.
  59. * 12-29-91 RID MAC module created, based on OS2 version
  60. * 01-10-92 GJF Merged. Also, added _C_Termination_Done [_WIN32_].
  61. * 02-13-92 GJF Moved all lowio initialization to ioinit.c for Win32.
  62. * 03-12-92 SKS Major changes to initialization/termination scheme
  63. * 04-01-92 XY implemented new intialization/termination schema (MAC)
  64. * 04-16-92 DJM POSIX support.
  65. * 04-17-92 SKS Export _initterm() for CRTDLL model
  66. * 05-07-92 DJM Removed _exit() from POSIX build.
  67. * 06-03-92 GJF Temporarily restored call to FORTRAN init.
  68. * 08-26-92 SKS Add _osver, _winver, _winmajor, _winminor
  69. * 08-28-92 GJF Use unistd.h for POSIX build.
  70. * 09-02-92 SKS Fix _onexit table traversal to be LIFO.
  71. * Since table is built forward (my changes 03-12-92)
  72. * the table must be traversed in reverse order.
  73. * 11-12-92 SKS Remove hard-coded call to FORTRAN initializer
  74. * 03-20-93 SKS Remove obsolete variables _osmode, _cpumode, etc.
  75. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  76. * 04-07-93 SKS Change to __declspec(dllexport) for CRT DLL model
  77. * 04-19-93 SKS Remove obsolete variable _child.
  78. * 04-20-93 SKS _C_Termination_Done is now used by DLLs in LIBC/LIBCMT
  79. * models, not just in MSVCRT10.DLL.
  80. * 07-16-93 SRW ALPHA Merge
  81. * 09-21-93 CFW Move _initmbctable call to _cinit().
  82. * 10-19-93 GJF Merged NT and Cuda versions. Cleaned out a lot of old
  83. * Cruiser and Dosx32 support. Replaced MTHREAD with
  84. * _MT, _MIPS_ with _M_MRX000, _ALPHA_ with _M_ALPHA.
  85. * 11-09-93 GJF Moved _initmbctable call back into crt0.c.
  86. * 11-09-93 GJF Replaced PF with _PVFV (defined in internal.h).
  87. * 11-19-93 CFW Add _wargv, _wpgmptr.
  88. * 11-29-93 CFW Add _wenviron.
  89. * 12-15-93 CFW Set _pgmptr, _wpgmptr to NULL (MIPS compiler bug).
  90. * 02-04-94 CFW Add _[w]initenv.
  91. * 03-25-94 GJF Made definitions of:
  92. * __argc,
  93. * __argv, __wargv,
  94. * _C_Termination_Done,
  95. * _environ, _wenviron,
  96. * _exitflag,
  97. * __initenv, __winitenv,
  98. * __onexitbegin, __onexitend,
  99. * _osver,
  100. * _pgmptr, _wpgmptr,
  101. * _winmajor,
  102. * _winminor
  103. * _winver
  104. * conditional on ndef DLL_FOR_WIN32S.
  105. * 10-02-94 BWT Add PPC changes
  106. * 12-03-94 SKS Clean up OS/2 references
  107. * 02-11-95 CFW PPC -> _M_MPPC.
  108. * 02-16-95 JWM Spliced _WIN32 & Mac versions.
  109. * 02-24-95 CFW Call _CrtDumpMemoryLeaks.
  110. * 02-27-95 CFW Make _CrtDumpMemoryLeaks call conditional
  111. * 04-06-95 CFW Only check for static libs, avoid infinite loop.
  112. * 07-24-95 CFW Call _CrtDumpMemoryLeaks for PMac.
  113. * 12-18-95 JWM doexit() can no longer be called recursively.
  114. * 08-01-96 RDK For PMac, define _osflagfiles, cleaned up Gestalt test,
  115. * and make termination parallel x86 functionality.
  116. * 07-24-97 GJF Added __env_initialized flag.
  117. * 08-06-97 GJF Moved __mbctype_initialized flag here from crt0.c.
  118. * 09-26-97 BWT Fix POSIX
  119. * 10-07-97 RDL Added IA64.
  120. * 01-16-98 RDL Removed IA64 from fpinit #if for _fltused support.
  121. * 10-02-98 GJF Added _osplatform.
  122. * 11-13-98 KBF Only do an atexit(RTC_Terminate) - moved Init to after
  123. * _heap_init
  124. * 02-01-99 GJF Slight change to terminator execution loop to allow
  125. * terminators to register more terminators.
  126. * 04-28-99 PML Wrap __declspec(allocate()) in _CRTALLOC macro.
  127. * 05-11-99 KBF Wrap RTC support in #ifdef.
  128. * 05-17-99 PML Remove all Macintosh support.
  129. * 03-06-00 PML Add __crtExitProcess for COM+ exit processing.
  130. * 04-28-00 BWT Fix Posix
  131. * 08-04-00 PML COM+ -> managed (VS7#117746).
  132. * 03-27-01 PML .CRT$XI funcs now return an error status (VS7#231220).
  133. * 05-01-01 BWT Remove TerminateProcess call. It's not necessary when
  134. * simply exiting would serve the same purpose.
  135. * 07-15-01 PML Remove all ALPHA, MIPS, and PPC code
  136. * 10-02-01 BWT Release exit critical section before calling __crtExitProcess
  137. * It's possible another thread may be calling doexit() while holding
  138. * the loader lock (static object construction on dllattach)
  139. * __crtExitProcess() needs to call GetModuleHandle to finish.
  140. * 11-06-01 GB Added __freeCRTMemory for debug build to minimize leaks
  141. * 04-29-02 GB Added try-finally arounds lock-unlock.
  142. *
  143. *******************************************************************************/
  144. #include <cruntime.h>
  145. #ifdef _POSIX_
  146. #include <unistd.h>
  147. #else
  148. #include <msdos.h>
  149. #include <rtcapi.h>
  150. #endif
  151. #include <dos.h>
  152. #include <oscalls.h>
  153. #include <mtdll.h>
  154. #include <internal.h>
  155. #include <stdio.h>
  156. #include <stdlib.h>
  157. #include <process.h>
  158. #include <dbgint.h>
  159. #include <sect_attribs.h>
  160. #include <mbctype.h>
  161. /* define errno */
  162. #ifndef _MT
  163. int errno = 0; /* libc error value */
  164. unsigned long _doserrno = 0; /* OS system error value */
  165. #endif /* _MT */
  166. /* define umask */
  167. int _umaskval = 0;
  168. /* define version info variables */
  169. _CRTIMP unsigned int _osplatform = 0;
  170. _CRTIMP unsigned int _osver = 0;
  171. _CRTIMP unsigned int _winver = 0;
  172. _CRTIMP unsigned int _winmajor = 0;
  173. _CRTIMP unsigned int _winminor = 0;
  174. /* argument vector and environment */
  175. _CRTIMP int __argc = 0;
  176. _CRTIMP char **__argv = NULL;
  177. _CRTIMP wchar_t **__wargv = NULL;
  178. #ifdef _POSIX_
  179. char **environ = NULL;
  180. #else
  181. _CRTIMP char **_environ = NULL;
  182. _CRTIMP char **__initenv = NULL;
  183. _CRTIMP wchar_t **_wenviron = NULL;
  184. _CRTIMP wchar_t **__winitenv = NULL;
  185. #endif
  186. _CRTIMP char *_pgmptr = NULL; /* ptr to program name */
  187. _CRTIMP wchar_t *_wpgmptr = NULL; /* ptr to wide program name */
  188. /* callable exit flag */
  189. char _exitflag = 0;
  190. /*
  191. * flag indicating if C runtime termination has been done. set if exit,
  192. * _exit, _cexit or _c_exit has been called. checked when _CRTDLL_INIT
  193. * is called with DLL_PROCESS_DETACH.
  194. */
  195. int _C_Termination_Done = FALSE;
  196. int _C_Exit_Done = FALSE;
  197. #ifndef CRTDLL
  198. /*
  199. * Flag checked by getenv() and _putenv() to determine if the environment has
  200. * been initialized.
  201. */
  202. int __env_initialized;
  203. #endif
  204. #ifdef _MBCS
  205. /*
  206. * Flag to ensure multibyte ctype table is only initialized once
  207. */
  208. int __mbctype_initialized;
  209. #endif /* _MBCS */
  210. /*
  211. * NOTE: THE USE OF THE POINTERS DECLARED BELOW DEPENDS ON THE PROPERTIES
  212. * OF C COMMUNAL VARIABLES. SPECIFICALLY, THEY ARE NON-NULL IFF THERE EXISTS
  213. * A DEFINITION ELSEWHERE INITIALIZING THEM TO NON-NULL VALUES.
  214. */
  215. /*
  216. * pointers to initialization functions
  217. */
  218. _PVFV _FPinit; /* floating point init. */
  219. /*
  220. * pointers to initialization sections
  221. */
  222. extern _CRTALLOC(".CRT$XIA") _PIFV __xi_a[];
  223. extern _CRTALLOC(".CRT$XIZ") _PIFV __xi_z[]; /* C initializers */
  224. extern _CRTALLOC(".CRT$XCA") _PVFV __xc_a[];
  225. extern _CRTALLOC(".CRT$XCZ") _PVFV __xc_z[]; /* C++ initializers */
  226. extern _CRTALLOC(".CRT$XPA") _PVFV __xp_a[];
  227. extern _CRTALLOC(".CRT$XPZ") _PVFV __xp_z[]; /* C pre-terminators */
  228. extern _CRTALLOC(".CRT$XTA") _PVFV __xt_a[];
  229. extern _CRTALLOC(".CRT$XTZ") _PVFV __xt_z[]; /* C terminators */
  230. /*
  231. * pointers to the start and finish of the _onexit/atexit table
  232. */
  233. _PVFV *__onexitbegin;
  234. _PVFV *__onexitend;
  235. /*
  236. * static (internal) functions that walk a table of function pointers,
  237. * calling each entry between the two pointers, skipping NULL entries
  238. *
  239. * _initterm needs to be exported for CRT DLL so that C++ initializers in the
  240. * client EXE / DLLs can be initialized.
  241. *
  242. * _initterm_e calls function pointers that return a nonzero error code to
  243. * indicate an initialization failed fatally.
  244. */
  245. #ifdef CRTDLL
  246. void __cdecl _initterm(_PVFV *, _PVFV *);
  247. #else
  248. static void __cdecl _initterm(_PVFV *, _PVFV *);
  249. #endif
  250. static int __cdecl _initterm_e(_PIFV *, _PIFV *);
  251. /***
  252. *_cinit - C initialization
  253. *
  254. *Purpose:
  255. * This routine performs the shared DOS and Windows initialization.
  256. * The following order of initialization must be preserved -
  257. *
  258. * 1. Check for devices for file handles 0 - 2
  259. * 2. Integer divide interrupt vector setup
  260. * 3. General C initializer routines
  261. *
  262. *Entry:
  263. * No parameters: Called from __crtstart and assumes data
  264. * set up correctly there.
  265. *
  266. *Exit:
  267. * Initializes C runtime data.
  268. * Returns 0 if all .CRT$XI internal initializations succeeded, else
  269. * the _RT_* fatal error code encountered.
  270. *
  271. *Exceptions:
  272. *
  273. *******************************************************************************/
  274. int __cdecl _cinit (
  275. void
  276. )
  277. {
  278. int initret;
  279. /*
  280. * initialize floating point package, if present
  281. */
  282. if ( _FPinit != NULL )
  283. (*_FPinit)();
  284. /*
  285. * do initializations
  286. */
  287. initret = _initterm_e( __xi_a, __xi_z );
  288. if ( initret != 0 )
  289. return initret;
  290. #ifdef _RTC
  291. atexit(_RTC_Terminate);
  292. #endif
  293. /*
  294. * do C++ initializations
  295. */
  296. _initterm( __xc_a, __xc_z );
  297. return 0;
  298. }
  299. /***
  300. *exit(status), _exit(status), _cexit(void), _c_exit(void) - C termination
  301. *
  302. *Purpose:
  303. *
  304. * Entry points:
  305. *
  306. * exit(code): Performs all the C termination functions
  307. * and terminates the process with the return code
  308. * supplied by the user.
  309. *
  310. * _exit(code): Performs a quick exit routine that does not
  311. * do certain 'high-level' exit processing. The _exit
  312. * routine terminates the process with the return code
  313. * supplied by the user.
  314. *
  315. * _cexit(): Performs the same C lib termination processing
  316. * as exit(code) but returns control to the caller
  317. * when done (i.e., does NOT terminate the process).
  318. *
  319. * _c_exit(): Performs the same C lib termination processing
  320. * as _exit(code) but returns control to the caller
  321. * when done (i.e., does NOT terminate the process).
  322. *
  323. * Termination actions:
  324. *
  325. * exit(), _cexit():
  326. *
  327. * 1. call user's terminator routines
  328. * 2. call C runtime preterminators
  329. *
  330. * _exit(), _c_exit():
  331. *
  332. * 3. call C runtime terminators
  333. * 4. return to DOS or caller
  334. *
  335. * Notes:
  336. *
  337. * The termination sequence is complicated due to the multiple entry
  338. * points sharing the common code body while having different entry/exit
  339. * sequences.
  340. *
  341. * Multi-thread notes:
  342. *
  343. * 1. exit() should NEVER be called when mthread locks are held.
  344. * The exit() routine can make calls that try to get mthread locks.
  345. *
  346. * 2. _exit()/_c_exit() can be called from anywhere, with or without locks held.
  347. * Thus, _exit() can NEVER try to get locks (otherwise, deadlock
  348. * may occur). _exit() should always 'work' (i.e., the process
  349. * should always terminate successfully).
  350. *
  351. * 3. Only one thread is allowed into the exit code (see _lockexit()
  352. * and _unlockexit() routines).
  353. *
  354. *Entry:
  355. * exit(), _exit()
  356. * int status - exit status (0-255)
  357. *
  358. * _cexit(), _c_exit()
  359. * <no input>
  360. *
  361. *Exit:
  362. * exit(), _exit()
  363. * <EXIT to DOS>
  364. *
  365. * _cexit(), _c_exit()
  366. * Return to caller
  367. *
  368. *Uses:
  369. *
  370. *Exceptions:
  371. *
  372. *******************************************************************************/
  373. /* worker routine prototype */
  374. static void __cdecl doexit (int code, int quick, int retcaller);
  375. void __cdecl exit (
  376. int code
  377. )
  378. {
  379. doexit(code, 0, 0); /* full term, kill process */
  380. }
  381. #ifndef _POSIX_
  382. void __cdecl _exit (
  383. int code
  384. )
  385. {
  386. doexit(code, 1, 0); /* quick term, kill process */
  387. }
  388. void __cdecl _cexit (
  389. void
  390. )
  391. {
  392. doexit(0, 0, 1); /* full term, return to caller */
  393. }
  394. void __cdecl _c_exit (
  395. void
  396. )
  397. {
  398. doexit(0, 1, 1); /* quick term, return to caller */
  399. }
  400. #endif /* _POSIX_ */
  401. #ifdef _DEBUG
  402. /***
  403. * __freeCrtMemory()
  404. *
  405. * Purpose:
  406. * To free as much as CRT memory as possible. This helps in keeping CRT leaks as
  407. * minimum.
  408. *
  409. *******************************************************************************/
  410. static void __freeCrtMemory()
  411. {
  412. void **pptr;
  413. for (pptr = _wenviron; pptr != NULL && *pptr != NULL; ++pptr) {
  414. _free_crt(*pptr);
  415. }
  416. _free_crt(_wenviron);
  417. #ifndef _POSIX_
  418. pptr = _environ;
  419. #else
  420. pptr = environ;
  421. #endif
  422. for (; pptr != NULL && *pptr != NULL; ++pptr) {
  423. _free_crt(*pptr);
  424. }
  425. #ifndef _POSIX_
  426. _free_crt(_environ);
  427. #else
  428. _free_crt(environ);
  429. #endif
  430. _free_crt(__wargv);
  431. _free_crt(__argv);
  432. _free_crt(__onexitbegin);
  433. _ioterm();
  434. #ifdef _MT
  435. _free_crt(__ptmbcinfo);
  436. #endif
  437. }
  438. #endif
  439. static void __cdecl doexit (
  440. int code,
  441. int quick,
  442. int retcaller
  443. )
  444. {
  445. #ifdef _DEBUG
  446. static int fExit = 0;
  447. #endif /* _DEBUG */
  448. #ifdef _MT
  449. _lockexit(); /* assure only 1 thread in exit path */
  450. __TRY
  451. #endif
  452. #ifndef _POSIX_
  453. if (_C_Exit_Done == TRUE) /* if doexit() is being called recursively */
  454. goto ExitBranch;
  455. #endif
  456. _C_Termination_Done = TRUE;
  457. /* save callable exit flag (for use by terminators) */
  458. _exitflag = (char) retcaller; /* 0 = term, !0 = callable exit */
  459. if (!quick) {
  460. /*
  461. * do _onexit/atexit() terminators
  462. * (if there are any)
  463. *
  464. * These terminators MUST be executed in reverse order (LIFO)!
  465. *
  466. * NOTE:
  467. * This code assumes that __onexitbegin points
  468. * to the first valid onexit() entry and that
  469. * __onexitend points past the last valid entry.
  470. * If __onexitbegin == __onexitend, the table
  471. * is empty and there are no routines to call.
  472. */
  473. if (__onexitbegin) {
  474. while ( --__onexitend >= __onexitbegin )
  475. /*
  476. * if current table entry is non-NULL,
  477. * call thru it.
  478. */
  479. if ( *__onexitend != NULL )
  480. (**__onexitend)();
  481. }
  482. #ifndef CRTDLL
  483. /*
  484. * do pre-terminators
  485. */
  486. _initterm(__xp_a, __xp_z);
  487. #endif
  488. }
  489. #ifndef CRTDLL
  490. /*
  491. * do terminators
  492. */
  493. _initterm(__xt_a, __xt_z);
  494. #endif
  495. #ifdef _DEBUG
  496. /* Dump all memory leaks */
  497. if (!fExit && _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) & _CRTDBG_LEAK_CHECK_DF)
  498. {
  499. fExit = 1;
  500. __freeCrtMemory();
  501. #ifndef CRTDLL
  502. _CrtDumpMemoryLeaks();
  503. #endif
  504. }
  505. #endif
  506. #ifndef _POSIX_
  507. ExitBranch: ;
  508. #endif
  509. /* return to OS or to caller */
  510. #ifdef _MT
  511. __FINALLY
  512. if (retcaller)
  513. _unlockexit(); /* unlock the exit code path */
  514. __END_TRY_FINALLY
  515. #endif
  516. if (retcaller)
  517. return;
  518. #ifdef _POSIX_
  519. _exit(code);
  520. }
  521. #else /* ndef _POSIX_ */
  522. _C_Exit_Done = TRUE;
  523. #ifdef _MT
  524. _unlockexit(); /* unlock the exit code path */
  525. #endif
  526. __crtExitProcess(code);
  527. }
  528. #ifdef CRTDLL
  529. void
  530. __CRTDLL_CallStaticTerminators(void) {
  531. /*
  532. * do pre-terminators
  533. */
  534. _initterm(__xp_a, __xp_z);
  535. /*
  536. * do terminators
  537. */
  538. _initterm(__xt_a, __xt_z);
  539. }
  540. #endif
  541. /***
  542. * __crtExitProcess - CRT wrapper for ExitProcess
  543. *
  544. *Purpose:
  545. * If we're part of a managed app, then call the CorExitProcess,
  546. * otherwise call ExitProcess. For managed apps, calling ExitProcess can
  547. * be problematic, because it doesn't give the managed FinalizerThread a
  548. * chance to clean up.
  549. *
  550. * To determine if we're a managed app, we check if mscoree.dll is loaded.
  551. * Then, if CorExitProcess is available, we call it.
  552. *
  553. *Entry:
  554. * int status - exit code
  555. *
  556. *Exit:
  557. * Does not return
  558. *
  559. *Exceptions:
  560. *
  561. *******************************************************************************/
  562. typedef void (WINAPI * PFN_EXIT_PROCESS)(UINT uExitCode);
  563. void __cdecl __crtExitProcess (
  564. int status
  565. )
  566. {
  567. HMODULE hmod;
  568. PFN_EXIT_PROCESS pfn;
  569. hmod = GetModuleHandle("mscoree.dll");
  570. if (hmod != NULL) {
  571. pfn = (PFN_EXIT_PROCESS)GetProcAddress(hmod, "CorExitProcess");
  572. if (pfn != NULL) {
  573. pfn(status);
  574. }
  575. }
  576. /*
  577. * Either mscoree.dll isn't loaded,
  578. * or CorExitProcess isn't exported from mscoree.dll,
  579. * or CorExitProcess returned (should never happen).
  580. * Just call ExitProcess.
  581. */
  582. ExitProcess(status);
  583. }
  584. #endif /* _POSIX_ */
  585. #ifdef _MT
  586. /***
  587. * _lockexit - Aquire the exit code lock
  588. *
  589. *Purpose:
  590. * Makes sure only one thread is in the exit code at a time.
  591. * If a thread is already in the exit code, it must be allowed
  592. * to continue. All other threads must pend.
  593. *
  594. * Notes:
  595. *
  596. * (1) It is legal for a thread that already has the lock to
  597. * try and get it again(!). That is, consider the following
  598. * sequence:
  599. *
  600. * (a) program calls exit()
  601. * (b) thread locks exit code
  602. * (c) user onexit() routine calls _exit()
  603. * (d) same thread tries to lock exit code
  604. *
  605. * Since _exit() must ALWAYS be able to work (i.e., can be called
  606. * from anywhere with no regard for locking), we must make sure the
  607. * program does not deadlock at step (d) above.
  608. *
  609. * (2) If a thread executing exit() or _exit() aquires the exit lock,
  610. * other threads trying to get the lock will pend forever. That is,
  611. * since exit() and _exit() terminate the process, there is not need
  612. * for them to unlock the exit code path.
  613. *
  614. * (3) Note that onexit()/atexit() routines call _lockexit/_unlockexit
  615. * to protect mthread access to the onexit table.
  616. *
  617. * (4) The 32-bit OS semaphore calls DO allow a single thread to acquire
  618. * the same lock multiple times* thus, this version is straight forward.
  619. *
  620. *Entry: <none>
  621. *
  622. *Exit:
  623. * Calling thread has exit code path locked on return.
  624. *
  625. *Exceptions:
  626. *
  627. *******************************************************************************/
  628. void __cdecl _lockexit (
  629. void
  630. )
  631. {
  632. _mlock(_EXIT_LOCK1);
  633. }
  634. /***
  635. * _unlockexit - Release exit code lock
  636. *
  637. *Purpose:
  638. * [See _lockexit() description above.]
  639. *
  640. * This routine is called by _cexit(), _c_exit(), and onexit()/atexit().
  641. * The exit() and _exit() routines never unlock the exit code path since
  642. * they are terminating the process.
  643. *
  644. *Entry:
  645. * Exit code path is unlocked.
  646. *
  647. *Exit:
  648. *
  649. *Exceptions:
  650. *
  651. *******************************************************************************/
  652. void __cdecl _unlockexit (
  653. void
  654. )
  655. {
  656. _munlock(_EXIT_LOCK1);
  657. }
  658. #endif /* _MT */
  659. /***
  660. * static void _initterm(_PVFV * pfbegin, _PVFV * pfend) - call entries in
  661. * function pointer table
  662. *
  663. *Purpose:
  664. * Walk a table of function pointers, calling each entry, as follows:
  665. *
  666. * 1. walk from beginning to end, pfunctbl is assumed to point
  667. * to the beginning of the table, which is currently a null entry,
  668. * as is the end entry.
  669. * 2. skip NULL entries
  670. * 3. stop walking when the end of the table is encountered
  671. *
  672. *Entry:
  673. * _PVFV *pfbegin - pointer to the beginning of the table (first
  674. * valid entry).
  675. * _PVFV *pfend - pointer to the end of the table (after last
  676. * valid entry).
  677. *
  678. *Exit:
  679. * No return value
  680. *
  681. *Notes:
  682. * This routine must be exported in the CRT DLL model so that the client
  683. * EXE and client DLL(s) can call it to initialize their C++ constructors.
  684. *
  685. *Exceptions:
  686. * If either pfbegin or pfend is NULL, or invalid, all bets are off!
  687. *
  688. *******************************************************************************/
  689. #ifdef CRTDLL
  690. void __cdecl _initterm (
  691. #else
  692. static void __cdecl _initterm (
  693. #endif
  694. _PVFV * pfbegin,
  695. _PVFV * pfend
  696. )
  697. {
  698. /*
  699. * walk the table of function pointers from the bottom up, until
  700. * the end is encountered. Do not skip the first entry. The initial
  701. * value of pfbegin points to the first valid entry. Do not try to
  702. * execute what pfend points to. Only entries before pfend are valid.
  703. */
  704. while ( pfbegin < pfend )
  705. {
  706. /*
  707. * if current table entry is non-NULL, call thru it.
  708. */
  709. if ( *pfbegin != NULL )
  710. (**pfbegin)();
  711. ++pfbegin;
  712. }
  713. }
  714. /***
  715. * static int _initterm_e(_PIFV * pfbegin, _PIFV * pfend) - call entries in
  716. * function pointer table, return error code on any failure
  717. *
  718. *Purpose:
  719. * Walk a table of function pointers in the same way as _initterm, but
  720. * here the functions return an error code. If an error is returned, it
  721. * will be a nonzero value equal to one of the _RT_* codes.
  722. *
  723. *Entry:
  724. * _PIFV *pfbegin - pointer to the beginning of the table (first
  725. * valid entry).
  726. * _PIFV *pfend - pointer to the end of the table (after last
  727. * valid entry).
  728. *
  729. *Exit:
  730. * No return value
  731. *
  732. *Notes:
  733. * This routine must be exported in the CRT DLL model so that the client
  734. * EXE and client DLL(s) can call it.
  735. *
  736. *Exceptions:
  737. * If either pfbegin or pfend is NULL, or invalid, all bets are off!
  738. *
  739. *******************************************************************************/
  740. static int __cdecl _initterm_e (
  741. _PIFV * pfbegin,
  742. _PIFV * pfend
  743. )
  744. {
  745. int ret = 0;
  746. /*
  747. * walk the table of function pointers from the bottom up, until
  748. * the end is encountered. Do not skip the first entry. The initial
  749. * value of pfbegin points to the first valid entry. Do not try to
  750. * execute what pfend points to. Only entries before pfend are valid.
  751. */
  752. while ( pfbegin < pfend && ret == 0)
  753. {
  754. /*
  755. * if current table entry is non-NULL, call thru it.
  756. */
  757. if ( *pfbegin != NULL )
  758. ret = (**pfbegin)();
  759. ++pfbegin;
  760. }
  761. return ret;
  762. }