Source code of Windows XP (NT5)
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.

518 lines
14 KiB

  1. /***
  2. *crt0dat.c - 32-bit C run-time initialization/termination routines
  3. *
  4. * Copyright (c) 1986-1992, 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. * *** FLOATING POINT INITIALIZATION AND TERMINATION ARE NOT ***
  16. * *** YET IMPLEMENTED IN THIS FILE ***
  17. *
  18. *Revision History:
  19. * 06-28-89 PHG Module created, based on asm version
  20. * 04-09-90 GJF Added #include <cruntime.h>. Made calling type
  21. * explicit (_CALLTYPE1 or _CALLTYPE4). Also, fixed
  22. * the copyright.
  23. * 04-10-90 GJF Fixed compiler warnings (-W3).
  24. * 05-21-90 GJF Added #undef _NFILE_ (temporary hack) and fixed the
  25. * indents.
  26. * 08-31-90 GJF Removed 32 from API names.
  27. * 09-25-90 GJF Merged tree version with local (8-31 and 5-21 changes).
  28. * 10-08-90 GJF New-style function declarators.
  29. * 10-12-90 GJF Removed divide by 0 stuff.
  30. * 10-18-90 GJF Added _pipech[] array.
  31. * 11-05-90 GJF Added _umaskval.
  32. * 12-04-90 GJF Added _osfinfo[] definition for Win32 target. Note that
  33. * the Win32 support is still incomplete!
  34. * 12-04-90 SRW Changed to include <oscalls.h> instead of <doscalls.h>
  35. * 12-04-90 SRW Added _osfile back for win32. Changed _osfinfo from
  36. * an array of structures to an array of 32-bit handles
  37. * (_osfhnd)
  38. * 12-28-90 SRW Added _CRUISER_ conditional around pack pragmas
  39. * 01-29-91 GJF ANSI naming.
  40. * 01-29-91 SRW Added call to GetFileType [_WIN32_]
  41. * 02-18-91 SRW Removed duplicate defintion of _NFILE_ (see os2dll.h)
  42. * 04-04-91 GJF Added definitions for _base[version|major|minor]
  43. * (_WIN32_).
  44. * 04-08-91 GJF Temporary hack for Win32/DOS folks - added HeapDestroy
  45. * call to doexit to tear down the OS heap used by C
  46. * heap.
  47. * 04-09-91 PNT Added _MAC_ conditional
  48. * 04-26-91 SRW Removed level 3 warnings
  49. * 07-16-91 GJF Added fp initialization test-and-call [_WIN32_].
  50. * 07-26-91 GJF Revised initialization and termination stuff. In
  51. * particular, removed need for win32ini.c [_WIN32_].
  52. * 08-07-91 GJF Added init. for FORTRAN runtime, if present [_WIN32_].
  53. * 08-21-91 GJF Test _prmtmp against NULL, not _prmtmp().
  54. * 08-21-91 JCR Added _exitflag, _endstdio, _cpumode, etc.
  55. * 09-09-91 GJF Revised _doinitterm for C++ init. support and to make
  56. * _onexit/atexit compatible with C++ needs.
  57. * 09-16-91 GJF Must test __onexitend before calling _doinitterm.
  58. * 10-29-91 GJF Force in floating point initialization for MIPS
  59. * compiler [_WIN32_].
  60. * 11-13-91 GJF FORTRAN needs _onexit/atexit init. before call thru
  61. * _pFFinit.
  62. * 01-10-92 GJF Merged. Also, added _C_Termination_Done [_WIN32_].
  63. * 02-13-92 GJF Moved all lowio initialization to ioinit.c for Win32.
  64. * 03-12-92 SKS Major changes to initialization/termination scheme
  65. * 04-16-92 DJM POSIX support.
  66. * 04-17-92 SKS Export _initterm() for CRTDLL model
  67. * 05-07-92 DJM Removed _exit() from POSIX build.
  68. * 06-03-92 GJF Temporarily restored call to FORTRAN init.
  69. * 08-26-92 SKS Add _osver, _winver, _winmajor, _winminor
  70. * 08-28-92 GJF Use unistd.h for POSIX build.
  71. * 09-02-92 SKS Fix _onexit table traversal to be LIFO.
  72. * Since table is built forward (my changes 03-12-92)
  73. * the table must be traversed in reverse order.
  74. * 10-30-92 TVB Force in floating point initialization for ALPHA
  75. * compiler as was done for MIPS. [_WIN32_].
  76. * 11-12-92 SKS Remove hard-coded call to FORTRAN initializer
  77. * 05-11-93 SKS _C_Termination_Done is now used by DLLs in LIBC/LIBCMT
  78. * models, not just in CRTDLL.DLL.
  79. * Remove obsolete variable _child.
  80. * 07-16-93 SRW ALPHA Merge
  81. *
  82. *******************************************************************************/
  83. #include <windows.h>
  84. #include <cruntime.h>
  85. #include <internal.h>
  86. #include <os2dll.h>
  87. /* callable exit flag */
  88. char _exitflag = 0;
  89. /*
  90. * flag indicating if C runtime termination has been done. set if exit,
  91. * _exit, _cexit or _c_exit has been called. checked when _CRTDLL_INIT
  92. * or user DLL's _CRT_INIT is called with DLL_PROCESS_DETACH.
  93. */
  94. int _C_Termination_Done = FALSE;
  95. /*
  96. * useful type for initialization and termination declarations
  97. */
  98. typedef void (_CALLTYPE1 *PF)(void);
  99. /*
  100. * NOTE: THE USE OF THE POINTERS DECLARED BELOW DEPENDS ON THE PROPERTIES
  101. * OF C COMMUNAL VARIABLES. SPECIFICALLY, THEY ARE NON-NULL IFF THERE EXISTS
  102. * A DEFINITION ELSEWHERE INITIALIZING THEM TO NON-NULL VALUES.
  103. */
  104. /*
  105. * pointers to initialization functions
  106. */
  107. PF _FPinit; /* floating point init. */
  108. /*
  109. * pointers to initialization sections
  110. */
  111. extern PF __xi_a[], __xi_z[]; /* C initializers */
  112. extern PF __xc_a[], __xc_z[]; /* C++ initializers */
  113. extern PF __xp_a[], __xp_z[]; /* C pre-terminators */
  114. extern PF __xt_a[], __xt_z[]; /* C terminators */
  115. #if defined(_M_MRX000) || defined(_M_ALPHA) || defined(_M_PPC)
  116. /*
  117. * For MIPS or ALPHA compilers, must explicitly force in and call the floating
  118. * point initialization (those system always have floating-point hardware).
  119. */
  120. extern void _CALLTYPE1 _fpmath(void);
  121. #endif
  122. /*
  123. * pointers to the start and finish of the _onexit/atexit table
  124. */
  125. PF *__onexitbegin;
  126. PF *__onexitend;
  127. /*
  128. * static (internal) function that walks a table of function pointers,
  129. * calling each entry between the two pointers, skipping NULL entries
  130. *
  131. * Needs to be exported for CRT DLL so that C++ initializers in the
  132. * client EXE / DLLs can be initialized
  133. */
  134. void _CALLTYPE4 _initterm(PF *, PF *);
  135. #pragma data_seg()
  136. /***
  137. *_cinit - C initialization
  138. *
  139. *Purpose:
  140. * This routine performs the shared DOS and Windows initialization.
  141. * The following order of initialization must be preserved -
  142. *
  143. ifdef MTHREAD
  144. * 0. Call OS2 to bump max file count (mthread only)
  145. endif
  146. * 1. Check for devices for file handles 0 - 2
  147. * 2. Integer divide interrupt vector setup
  148. * 3. General C initializer routines
  149. *
  150. *Entry:
  151. * No parameters: Called from __crtstart and assumes data
  152. * set up correctly there.
  153. *
  154. *Exit:
  155. * Initializes C runtime data.
  156. *
  157. *Exceptions:
  158. *
  159. *******************************************************************************/
  160. void _CALLTYPE1 _cinit (
  161. void
  162. )
  163. {
  164. /*
  165. * initialize floating point package, if present
  166. */
  167. #if defined(_M_MRX000) || defined(_M_ALPHA) || defined(_M_PPC)
  168. /*
  169. * The Mips, Alpha, and PPC compilers don't emit external reference to
  170. * _fltused. Therefore, must always force in the floating point
  171. * initialization.
  172. */
  173. _fpmath();
  174. #else
  175. if ( _FPinit != NULL )
  176. (*_FPinit)();
  177. #endif
  178. /*
  179. * do initializations
  180. */
  181. _initterm( __xi_a, __xi_z );
  182. /*
  183. * do C++ initializations
  184. */
  185. _initterm( __xc_a, __xc_z );
  186. }
  187. /***
  188. *exit(status), _exit(status), _cexit(void), _c_exit(void) - C termination
  189. *
  190. *Purpose:
  191. *
  192. * Entry points:
  193. *
  194. * exit(code): Performs all the C termination functions
  195. * and terminates the process with the return code
  196. * supplied by the user.
  197. *
  198. * _exit(code): Performs a quick exit routine that does not
  199. * do certain 'high-level' exit processing. The _exit
  200. * routine terminates the process with the return code
  201. * supplied by the user.
  202. *
  203. * _cexit(): Performs the same C lib termination processing
  204. * as exit(code) but returns control to the caller
  205. * when done (i.e., does NOT terminate the process).
  206. *
  207. * _c_exit(): Performs the same C lib termination processing
  208. * as _exit(code) but returns control to the caller
  209. * when done (i.e., does NOT terminate the process).
  210. *
  211. * Termination actions:
  212. *
  213. * exit(), _cexit():
  214. *
  215. * 1. call user's terminator routines
  216. * 2. call C runtime preterminators
  217. *
  218. * _exit(), _c_exit():
  219. *
  220. * 3. call C runtime terminators
  221. * 4. return to DOS or caller
  222. *
  223. * Notes:
  224. *
  225. * The termination sequence is complicated due to the multiple entry
  226. * points sharing the common code body while having different entry/exit
  227. * sequences.
  228. *
  229. * Multi-thread notes:
  230. *
  231. * 1. exit() should NEVER be called when mthread locks are held.
  232. * The exit() routine can make calls that try to get mthread locks.
  233. *
  234. * 2. _exit()/_c_exit() can be called from anywhere, with or without locks held.
  235. * Thus, _exit() can NEVER try to get locks (otherwise, deadlock
  236. * may occur). _exit() should always 'work' (i.e., the process
  237. * should always terminate successfully).
  238. *
  239. * 3. Only one thread is allowed into the exit code (see _lockexit()
  240. * and _unlockexit() routines).
  241. *
  242. *Entry:
  243. * exit(), _exit()
  244. * int status - exit status (0-255)
  245. *
  246. * _cexit(), _c_exit()
  247. * <no input>
  248. *
  249. *Exit:
  250. * exit(), _exit()
  251. * <EXIT to DOS>
  252. *
  253. * _cexit(), _c_exit()
  254. * Return to caller
  255. *
  256. *Uses:
  257. *
  258. *Exceptions:
  259. *
  260. *******************************************************************************/
  261. /* worker routine prototype */
  262. static void _CALLTYPE4 doexit (int code, int quick, int retcaller);
  263. void _CALLTYPE1 exit (
  264. int code
  265. )
  266. {
  267. doexit(code, 0, 0); /* full term, kill process */
  268. }
  269. #ifndef _POSIX_
  270. void _CALLTYPE1 _exit (
  271. int code
  272. )
  273. {
  274. doexit(code, 1, 0); /* quick term, kill process */
  275. }
  276. void _CALLTYPE1 _cexit (
  277. void
  278. )
  279. {
  280. doexit(0, 0, 1); /* full term, return to caller */
  281. }
  282. void _CALLTYPE1 _c_exit (
  283. void
  284. )
  285. {
  286. doexit(0, 1, 1); /* quick term, return to caller */
  287. }
  288. #endif /* _POSIX_ */
  289. static void _CALLTYPE4 doexit (
  290. int code,
  291. int quick,
  292. int retcaller
  293. )
  294. {
  295. _lockexit(); /* assure only 1 thread in exit path */
  296. /* save callable exit flag (for use by terminators) */
  297. _exitflag = (char) retcaller; /* 0 = term, !0 = callable exit */
  298. if (!quick) {
  299. /*
  300. * do _onexit/atexit() terminators
  301. * (if there are any)
  302. *
  303. * These terminators MUST be executed in reverse order (LIFO)!
  304. *
  305. * NOTE:
  306. * This code assumes that __onexitbegin points
  307. * to the first valid onexit() entry and that
  308. * __onexitend points past the last valid entry.
  309. * If __onexitbegin == __onexitend, the table
  310. * is empty and there are no routines to call.
  311. */
  312. if (__onexitbegin) {
  313. PF * pfend = __onexitend;
  314. while ( -- pfend >= __onexitbegin )
  315. /*
  316. * if current table entry is non-NULL,
  317. * call thru it.
  318. */
  319. if ( *pfend != NULL )
  320. (**pfend)();
  321. }
  322. /*
  323. * do pre-terminators
  324. */
  325. _initterm(__xp_a, __xp_z);
  326. }
  327. /*
  328. * do terminators
  329. */
  330. _initterm(__xt_a, __xt_z);
  331. /********** FLOATING POINT TERMINATION SHOULD GO HERE ************/
  332. /* return to OS/2 or to caller */
  333. if (retcaller) {
  334. _unlockexit(); /* unlock the exit code path */
  335. return;
  336. }
  337. ExitProcess(code);
  338. }
  339. /***
  340. * _lockexit - Aquire the exit code lock
  341. *
  342. *Purpose:
  343. * Makes sure only one thread is in the exit code at a time.
  344. * If a thread is already in the exit code, it must be allowed
  345. * to continue. All other threads must pend.
  346. *
  347. * Notes:
  348. *
  349. * (1) It is legal for a thread that already has the lock to
  350. * try and get it again(!). That is, consider the following
  351. * sequence:
  352. *
  353. * (a) program calls exit()
  354. * (b) thread locks exit code
  355. * (c) user onexit() routine calls _exit()
  356. * (d) same thread tries to lock exit code
  357. *
  358. * Since _exit() must ALWAYS be able to work (i.e., can be called
  359. * from anywhere with no regard for locking), we must make sure the
  360. * program does not deadlock at step (d) above.
  361. *
  362. * (2) If a thread executing exit() or _exit() aquires the exit lock,
  363. * other threads trying to get the lock will pend forever. That is,
  364. * since exit() and _exit() terminate the process, there is not need
  365. * for them to unlock the exit code path.
  366. *
  367. * (3) Note that onexit()/atexit() routines call _lockexit/_unlockexit
  368. * to protect mthread access to the onexit table.
  369. *
  370. * (4) The _lockexit/_unlockexit routines are very complicated in 286
  371. * OS/2 since a thread that held a lock could not request the lock again.
  372. * The 32-bit OS/2 semaphore calls DO allow a single thread to aquire the
  373. * same lock multiple times* thus, this version is straight forward.
  374. *
  375. *Entry: <none>
  376. *
  377. *Exit:
  378. * Calling thread has exit code path locked on return.
  379. *
  380. *Exceptions:
  381. *
  382. *******************************************************************************/
  383. void _CALLTYPE1 _lockexit (
  384. void
  385. )
  386. {
  387. _mlock(_EXIT_LOCK1);
  388. }
  389. /***
  390. * _unlockexit - Release exit code lock
  391. *
  392. *Purpose:
  393. * [See _lockexit() description above.]
  394. *
  395. * This routine is called by _cexit(), _c_exit(), and onexit()/atexit().
  396. * The exit() and _exit() routines never unlock the exit code path since
  397. * they are terminating the process.
  398. *
  399. *Entry:
  400. * Exit code path is unlocked.
  401. *
  402. *Exit:
  403. *
  404. *Exceptions:
  405. *
  406. *******************************************************************************/
  407. void _CALLTYPE1 _unlockexit (
  408. void
  409. )
  410. {
  411. _munlock(_EXIT_LOCK1);
  412. }
  413. /***
  414. * static void _initterm(PF * pfbegin, PF * pfend) - call entries in
  415. * function pointer table
  416. *
  417. *Purpose:
  418. * Walk a table of function pointers, calling each entry, as follows:
  419. *
  420. * 1. walk from beginning to end, pfunctbl is assumed to point
  421. * to the beginning of the table, which is currently a null entry,
  422. * as is the end entry.
  423. * 2. skip NULL entries
  424. * 3. stop walking when the end of the table is encountered
  425. *
  426. *Entry:
  427. * PF *pfbegin - pointer to the beginning of the table (first valid entry).
  428. * PF *pfend - pointer to the end of the table (after last valid entry).
  429. *
  430. *Exit:
  431. * No return value
  432. *
  433. *Notes:
  434. * This routine must be exported in the CRT DLL model so that the client
  435. * EXE and client DLL(s) can call it to initialize their C++ constructors.
  436. *
  437. *Exceptions:
  438. * If either pfbegin or pfend is NULL, or invalid, all bets are off!
  439. *
  440. *******************************************************************************/
  441. void _CALLTYPE4 _initterm (
  442. PF * pfbegin,
  443. PF * pfend
  444. )
  445. {
  446. /*
  447. * walk the table of function pointers from the bottom up, until
  448. * the end is encountered. Do not skip the first entry. The initial
  449. * value of pfbegin points to the first valid entry. Do not try to
  450. * execute what pfend points to. Only entries before pfend are valid.
  451. */
  452. while ( pfbegin < pfend )
  453. {
  454. /*
  455. * if current table entry is non-NULL, call thru it.
  456. */
  457. if ( *pfbegin != NULL )
  458. (**pfbegin)();
  459. ++pfbegin;
  460. }
  461. }