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

  1. /***
  2. *crt0dat.c - 32-bit C run-time initialization/termination routines
  3. *
  4. *       Copyright (c) 1986-1997, 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 THE MAC VERSION                    ***
  17. *
  18. *******************************************************************************/
  19.  
  20. #ifdef _WIN32
  21.  
  22. #include <cruntime.h>
  23. #include <msdos.h>
  24. #include <dos.h>
  25. #include <oscalls.h>
  26. #include <mtdll.h>
  27. #include <internal.h>
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <process.h>
  31. #include <dbgint.h>
  32.  
  33.  
  34. /* define errno */
  35. #ifndef _MT
  36. int errno = 0;            /* libc error value */
  37. unsigned long _doserrno = 0;  /* OS system error value */
  38. #endif  /* _MT */
  39.  
  40.  
  41. /* define umask */
  42. int _umaskval = 0;
  43.  
  44.  
  45. /* define version info variables */
  46.  
  47. _CRTIMP unsigned int _osver = 0;
  48. _CRTIMP unsigned int _winver = 0;
  49. _CRTIMP unsigned int _winmajor = 0;
  50. _CRTIMP unsigned int _winminor = 0;
  51.  
  52.  
  53. /* argument vector and environment */
  54.  
  55. _CRTIMP int __argc = 0;
  56. _CRTIMP char **__argv = NULL;
  57. _CRTIMP wchar_t **__wargv = NULL;
  58. _CRTIMP char **_environ = NULL;
  59. _CRTIMP char **__initenv = NULL;
  60. _CRTIMP wchar_t **_wenviron = NULL;
  61. _CRTIMP wchar_t **__winitenv = NULL;
  62. _CRTIMP char *_pgmptr = NULL;           /* ptr to program name */
  63. _CRTIMP wchar_t *_wpgmptr = NULL;       /* ptr to wide program name */
  64.  
  65.  
  66. /* callable exit flag */
  67. char _exitflag = 0;
  68.  
  69. /*
  70.  * flag indicating if C runtime termination has been done. set if exit,
  71.  * _exit, _cexit or _c_exit has been called. checked when _CRTDLL_INIT
  72.  * is called with DLL_PROCESS_DETACH.
  73.  */
  74. int _C_Termination_Done = FALSE;
  75. int _C_Exit_Done = FALSE;
  76.  
  77. #ifndef CRTDLL
  78. /*
  79.  * Flag checked by getenv() and _putenv() to determine if the environment has
  80.  * been initialized.
  81.  */
  82. int __env_initialized;
  83.  
  84. #endif  /* CRTDLL */
  85.  
  86. #ifdef _MBCS
  87. /*
  88.  * Flag to ensure multibyte ctype table is only initialized once
  89.  */
  90. int __mbctype_initialized;
  91. #endif  /* _MBCS */
  92.  
  93.  
  94. /*
  95.  * NOTE: THE USE OF THE POINTERS DECLARED BELOW DEPENDS ON THE PROPERTIES
  96.  * OF C COMMUNAL VARIABLES. SPECIFICALLY, THEY ARE NON-NULL IFF THERE EXISTS
  97.  * A DEFINITION ELSEWHERE INITIALIZING THEM TO NON-NULL VALUES.
  98.  */
  99.  
  100. /*
  101.  * pointers to initialization functions
  102.  */
  103.  
  104. _PVFV _FPinit;          /* floating point init. */
  105.  
  106. /*
  107.  * pointers to initialization sections
  108.  */
  109.  
  110. extern _PVFV __xi_a[], __xi_z[];    /* C initializers */
  111. extern _PVFV __xc_a[], __xc_z[];    /* C++ initializers */
  112. extern _PVFV __xp_a[], __xp_z[];    /* C pre-terminators */
  113. extern _PVFV __xt_a[], __xt_z[];    /* C terminators */
  114.  
  115. #if defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC)
  116. /*
  117.  * For MIPS compiler, must explicitly force in and call the floating point
  118.  * initialization.
  119.  */
  120. extern void __cdecl _fpmath(void);
  121. #endif  /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) */
  122.  
  123. /*
  124.  * pointers to the start and finish of the _onexit/atexit table
  125.  */
  126. _PVFV *__onexitbegin;
  127. _PVFV *__onexitend;
  128.  
  129.  
  130. /*
  131.  * static (internal) function that walks a table of function pointers,
  132.  * calling each entry between the two pointers, skipping NULL entries
  133.  *
  134.  * Needs to be exported for CRT DLL so that C++ initializers in the
  135.  * client EXE / DLLs can be initialized
  136.  */
  137. #ifdef CRTDLL
  138. void __cdecl _initterm(_PVFV *, _PVFV *);
  139. #else  /* CRTDLL */
  140. static void __cdecl _initterm(_PVFV *, _PVFV *);
  141. #endif  /* CRTDLL */
  142.  
  143.  
  144. /***
  145. *_cinit - C initialization
  146. *
  147. *Purpose:
  148. *       This routine performs the shared DOS and Windows initialization.
  149. *       The following order of initialization must be preserved -
  150. *
  151. *       1.  Check for devices for file handles 0 - 2
  152. *       2.  Integer divide interrupt vector setup
  153. *       3.  General C initializer routines
  154. *
  155. *Entry:
  156. *       No parameters: Called from __crtstart and assumes data
  157. *       set up correctly there.
  158. *
  159. *Exit:
  160. *       Initializes C runtime data.
  161. *
  162. *Exceptions:
  163. *
  164. *******************************************************************************/
  165.  
  166. void __cdecl _cinit (
  167.         void
  168.         )
  169. {
  170.         /*
  171.          * initialize floating point package, if present
  172.          */
  173. #if defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC)
  174.         /*
  175.          * MIPS compiler doesn't emit external reference to _fltused. Therefore,
  176.          * must always force in the floating point initialization.
  177.          */
  178.         _fpmath();
  179. #else  /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) */
  180.         if ( _FPinit != NULL )
  181.             (*_FPinit)();
  182. #endif  /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) */
  183.  
  184.         /*
  185.          * do initializations
  186.          */
  187.         _initterm( __xi_a, __xi_z );
  188.  
  189.         /*
  190.          * do C++ initializations
  191.          */
  192.         _initterm( __xc_a, __xc_z );
  193.  
  194. }
  195.  
  196.  
  197. /***
  198. *exit(status), _exit(status), _cexit(void), _c_exit(void) - C termination
  199. *
  200. *Purpose:
  201. *
  202. *       Entry points:
  203. *
  204. *           exit(code):  Performs all the C termination functions
  205. *               and terminates the process with the return code
  206. *               supplied by the user.
  207. *
  208. *           _exit(code):  Performs a quick exit routine that does not
  209. *               do certain 'high-level' exit processing.  The _exit
  210. *               routine terminates the process with the return code
  211. *               supplied by the user.
  212. *
  213. *           _cexit():  Performs the same C lib termination processing
  214. *               as exit(code) but returns control to the caller
  215. *               when done (i.e., does NOT terminate the process).
  216. *
  217. *           _c_exit():  Performs the same C lib termination processing
  218. *               as _exit(code) but returns control to the caller
  219. *               when done (i.e., does NOT terminate the process).
  220. *
  221. *       Termination actions:
  222. *
  223. *           exit(), _cexit():
  224. *
  225. *           1.  call user's terminator routines
  226. *           2.  call C runtime preterminators
  227. *
  228. *           _exit(), _c_exit():
  229. *
  230. *           3.  call C runtime terminators
  231. *           4.  return to DOS or caller
  232. *
  233. *       Notes:
  234. *
  235. *       The termination sequence is complicated due to the multiple entry
  236. *       points sharing the common code body while having different entry/exit
  237. *       sequences.
  238. *
  239. *       Multi-thread notes:
  240. *
  241. *       1. exit() should NEVER be called when mthread locks are held.
  242. *          The exit() routine can make calls that try to get mthread locks.
  243. *
  244. *       2. _exit()/_c_exit() can be called from anywhere, with or without locks held.
  245. *          Thus, _exit() can NEVER try to get locks (otherwise, deadlock
  246. *          may occur).  _exit() should always 'work' (i.e., the process
  247. *          should always terminate successfully).
  248. *
  249. *       3. Only one thread is allowed into the exit code (see _lockexit()
  250. *          and _unlockexit() routines).
  251. *
  252. *Entry:
  253. *       exit(), _exit()
  254. *           int status - exit status (0-255)
  255. *
  256. *       _cexit(), _c_exit()
  257. *           <no input>
  258. *
  259. *Exit:
  260. *       exit(), _exit()
  261. *           <EXIT to DOS>
  262. *
  263. *       _cexit(), _c_exit()
  264. *           Return to caller
  265. *
  266. *Uses:
  267. *
  268. *Exceptions:
  269. *
  270. *******************************************************************************/
  271.  
  272. /* worker routine prototype */
  273. static void __cdecl doexit (int code, int quick, int retcaller);
  274.  
  275. void __cdecl exit (
  276.         int code
  277.         )
  278. {
  279.         doexit(code, 0, 0); /* full term, kill process */
  280. }
  281.  
  282.  
  283. void __cdecl _exit (
  284.         int code
  285.         )
  286. {
  287.         doexit(code, 1, 0); /* quick term, kill process */
  288. }
  289.  
  290. void __cdecl _cexit (
  291.         void
  292.         )
  293. {
  294.         doexit(0, 0, 1);    /* full term, return to caller */
  295. }
  296.  
  297. void __cdecl _c_exit (
  298.         void
  299.         )
  300. {
  301.         doexit(0, 1, 1);    /* quick term, return to caller */
  302. }
  303.  
  304.  
  305.  
  306. static void __cdecl doexit (
  307.         int code,
  308.         int quick,
  309.         int retcaller
  310.         )
  311. {
  312. #ifdef _DEBUG
  313.         static int fExit = 0;
  314. #endif  /* _DEBUG */
  315.  
  316. #ifdef _MT
  317.         _lockexit();        /* assure only 1 thread in exit path */
  318. #endif  /* _MT */
  319.  
  320.         if (_C_Exit_Done == TRUE)                               /* if doexit() is being called recursively */
  321.                 TerminateProcess(GetCurrentProcess(),code);     /* terminate with extreme prejudice */
  322.         _C_Termination_Done = TRUE;
  323.  
  324.         /* save callable exit flag (for use by terminators) */
  325.         _exitflag = (char) retcaller;  /* 0 = term, !0 = callable exit */
  326.  
  327.         if (!quick) {
  328.  
  329.             /*
  330.              * do _onexit/atexit() terminators
  331.              * (if there are any)
  332.              *
  333.              * These terminators MUST be executed in reverse order (LIFO)!
  334.              *
  335.              * NOTE:
  336.              *  This code assumes that __onexitbegin points
  337.              *  to the first valid onexit() entry and that
  338.              *  __onexitend points past the last valid entry.
  339.              *  If __onexitbegin == __onexitend, the table
  340.              *  is empty and there are no routines to call.
  341.              */
  342.  
  343.             if (__onexitbegin) {
  344.                 _PVFV * pfend = __onexitend;
  345.  
  346.                 while ( --pfend >= __onexitbegin )
  347.                 /*
  348.                  * if current table entry is non-NULL,
  349.                  * call thru it.
  350.                  */
  351.                 if ( *pfend != NULL )
  352.                     (**pfend)();
  353.             }
  354.  
  355.             /*
  356.              * do pre-terminators
  357.              */
  358.             _initterm(__xp_a, __xp_z);
  359.         }
  360.  
  361.         /*
  362.          * do terminators
  363.          */
  364.         _initterm(__xt_a, __xt_z);
  365.  
  366. #ifndef CRTDLL
  367. #ifdef _DEBUG
  368.         /* Dump all memory leaks */
  369.         if (!fExit && _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) & _CRTDBG_LEAK_CHECK_DF)
  370.         {
  371.             fExit = 1;
  372.             _CrtDumpMemoryLeaks();
  373.         }
  374. #endif  /* _DEBUG */
  375. #endif  /* CRTDLL */
  376.  
  377.         /* return to OS or to caller */
  378.  
  379.         if (retcaller) {
  380. #ifdef _MT
  381.             _unlockexit();      /* unlock the exit code path */
  382. #endif  /* _MT */
  383.             return;
  384.         }
  385.  
  386.  
  387.         _C_Exit_Done = TRUE;
  388.  
  389.         ExitProcess(code);
  390.  
  391.  
  392. }
  393.  
  394. #ifdef _MT
  395. /***
  396. * _lockexit - Aquire the exit code lock
  397. *
  398. *Purpose:
  399. *       Makes sure only one thread is in the exit code at a time.
  400. *       If a thread is already in the exit code, it must be allowed
  401. *       to continue.  All other threads must pend.
  402. *
  403. *       Notes:
  404. *
  405. *       (1) It is legal for a thread that already has the lock to
  406. *       try and get it again(!).  That is, consider the following
  407. *       sequence:
  408. *
  409. *           (a) program calls exit()
  410. *           (b) thread locks exit code
  411. *           (c) user onexit() routine calls _exit()
  412. *           (d) same thread tries to lock exit code
  413. *
  414. *       Since _exit() must ALWAYS be able to work (i.e., can be called
  415. *       from anywhere with no regard for locking), we must make sure the
  416. *       program does not deadlock at step (d) above.
  417. *
  418. *       (2) If a thread executing exit() or _exit() aquires the exit lock,
  419. *       other threads trying to get the lock will pend forever.  That is,
  420. *       since exit() and _exit() terminate the process, there is not need
  421. *       for them to unlock the exit code path.
  422. *
  423. *       (3) Note that onexit()/atexit() routines call _lockexit/_unlockexit
  424. *       to protect mthread access to the onexit table.
  425. *
  426. *       (4) The 32-bit OS semaphore calls DO allow a single thread to acquire
  427. *       the same lock multiple times* thus, this version is straight forward.
  428. *
  429. *Entry: <none>
  430. *
  431. *Exit:
  432. *       Calling thread has exit code path locked on return.
  433. *
  434. *Exceptions:
  435. *
  436. *******************************************************************************/
  437.  
  438. void __cdecl _lockexit (
  439.         void
  440.         )
  441. {
  442.         _mlock(_EXIT_LOCK1);
  443. }
  444.  
  445. /***
  446. * _unlockexit - Release exit code lock
  447. *
  448. *Purpose:
  449. *       [See _lockexit() description above.]
  450. *
  451. *       This routine is called by _cexit(), _c_exit(), and onexit()/atexit().
  452. *       The exit() and _exit() routines never unlock the exit code path since
  453. *       they are terminating the process.
  454. *
  455. *Entry:
  456. *       Exit code path is unlocked.
  457. *
  458. *Exit:
  459. *
  460. *Exceptions:
  461. *
  462. *******************************************************************************/
  463.  
  464. void __cdecl _unlockexit (
  465.         void
  466.         )
  467. {
  468.         _munlock(_EXIT_LOCK1);
  469. }
  470.  
  471. #endif  /* _MT */
  472.  
  473.  
  474. /***
  475. * static void _initterm(_PVFV * pfbegin, _PVFV * pfend) - call entries in
  476. *       function pointer table
  477. *
  478. *Purpose:
  479. *       Walk a table of function pointers, calling each entry, as follows:
  480. *
  481. *           1. walk from beginning to end, pfunctbl is assumed to point
  482. *              to the beginning of the table, which is currently a null entry,
  483. *              as is the end entry.
  484. *           2. skip NULL entries
  485. *           3. stop walking when the end of the table is encountered
  486. *
  487. *Entry:
  488. *       _PVFV *pfbegin  - pointer to the beginning of the table (first valid entry).
  489. *       _PVFV *pfend    - pointer to the end of the table (after last valid entry).
  490. *
  491. *Exit:
  492. *       No return value
  493. *
  494. *Notes:
  495. *       This routine must be exported in the CRT DLL model so that the client
  496. *       EXE and client DLL(s) can call it to initialize their C++ constructors.
  497. *
  498. *Exceptions:
  499. *       If either pfbegin or pfend is NULL, or invalid, all bets are off!
  500. *
  501. *******************************************************************************/
  502.  
  503. #ifdef CRTDLL
  504. void __cdecl _initterm (
  505. #else  /* CRTDLL */
  506. static void __cdecl _initterm (
  507. #endif  /* CRTDLL */
  508.         _PVFV * pfbegin,
  509.         _PVFV * pfend
  510.         )
  511. {
  512.         /*
  513.          * walk the table of function pointers from the bottom up, until
  514.          * the end is encountered.  Do not skip the first entry.  The initial
  515.          * value of pfbegin points to the first valid entry.  Do not try to
  516.          * execute what pfend points to.  Only entries before pfend are valid.
  517.          */
  518.         while ( pfbegin < pfend )
  519.         {
  520.             /*
  521.              * if current table entry is non-NULL, call thru it.
  522.              */
  523.             if ( *pfbegin != NULL )
  524.                 (**pfbegin)();
  525.             ++pfbegin;
  526.         }
  527. }
  528.  
  529. #else  /* _WIN32 */
  530.  
  531. #include <cruntime.h>
  532. #include <msdos.h>
  533. #include <stdio.h>
  534. #include <stdlib.h>
  535. #include <internal.h>
  536. #include <fltintrn.h>
  537. #include <mpw.h>
  538. #include <mtdll.h>
  539. #include <macos\types.h>
  540. #include <macos\segload.h>
  541. #include <macos\gestalte.h>
  542. #include <macos\osutils.h>
  543. #include <macos\traps.h>
  544. #include <dbgint.h>
  545.  
  546. /* define errno */
  547.  
  548. int _VARTYPE1 errno = 0;                /* libc error value */
  549. int _VARTYPE1 _macerrno = 0;    /* OS system error value */
  550.  
  551. /* define umask */
  552. int _umaskval = 0;
  553.  
  554. /* define version info variables */
  555. unsigned int _VARTYPE1 _osver = 0;
  556. //unsigned int _VARTYPE1 _osversion = 0;
  557. //unsigned int _VARTYPE1 _osmajor = 0;
  558. //unsigned int _VARTYPE1 _osminor = 0;
  559.  
  560. /* exprot them as in C7*/
  561. int __argc = 0;
  562. char **__argv = NULL;
  563.  
  564. /* number of allowable file handles */
  565. int _nfile = _NHANDLE_;
  566.  
  567. /* file handle database -- stdout, stdin, stderr are NOT open */
  568. char _osfile[_NHANDLE_] = {(unsigned char)(FOPEN+FTEXT), (unsigned char)(FOPEN+FTEXT), (unsigned char)(FOPEN+FTEXT)};
  569. int _osfhnd [_NHANDLE_] = {-1, -1, -1};
  570. unsigned char _osperm [_NHANDLE_];
  571. short _osVRefNum [_NHANDLE_];
  572. unsigned char _osfileflags[_NHANDLE_];
  573.  
  574. /* environment pointer */
  575. char **_environ = NULL;
  576.  
  577. char _exitflag = 0;
  578.  
  579. /* MPW block pointer */
  580.  
  581. MPWBLOCK * _pMPWBlock = NULL;
  582.  
  583.  
  584. /*
  585.  * pointers to initialization functions
  586.  */
  587.  
  588. extern PFV __xi_a ;
  589.  
  590. extern PFV __xi_z ;
  591.  
  592. extern PFV __xc_a ;  /* C++ initializers */
  593.  
  594. extern PFV __xc_z ;
  595.  
  596. extern PFV __xp_a ;  /* C pre-terminators */
  597.  
  598. extern PFV __xp_z ;
  599.  
  600. extern PFV __xt_a ;   /* C terminators */
  601.  
  602. extern PFV __xt_z ;
  603.  
  604.  
  605.  
  606.  
  607. /*
  608.  * pointers to the start and finish of the _onexit/atexit table
  609.  */
  610. extern PFV *__onexitbegin;
  611. extern PFV *__onexitend;
  612.  
  613. #ifndef _M_MPPC
  614. static void _CALLTYPE4 _initterm(PFV *, PFV *);
  615. #else  /* _M_MPPC */
  616. void _CALLTYPE4 _initterm(PFV *, PFV *);
  617. #endif  /* _M_MPPC */
  618.  
  619. /***
  620. *_cinit - C initialization
  621. *
  622. *Purpose:
  623. *       This routine performs the shared DOS and Windows initialization.
  624. *       The following order of initialization must be preserved -
  625. *
  626. *    ?  1.      Check for devices for file handles 0 - 2
  627. *    ?  2.      Integer divide interrupt vector setup
  628. *       3.      General C initializer routines
  629. *
  630. *Entry:
  631. *       No parameters: Called from __crtstart and assumes data
  632. *       set up correctly there.
  633. *
  634. *Exit:
  635. *       Initializes C runtime data.
  636. *
  637. *Exceptions:
  638. *
  639. *******************************************************************************/
  640. int _CALLTYPE1 __cinit (
  641.         void
  642.         )
  643. {
  644.         long lRespond;
  645.         OSErr osErr;
  646.  
  647.         /*
  648.          * do initializations
  649.          */
  650.         _initterm( &__xi_a, &__xi_z );
  651.  
  652.         /*
  653.          * do C++ initializations
  654.          */
  655.         _initterm( &__xc_a, &__xc_z );
  656.  
  657.         osErr = Gestalt(gestaltSystemVersion, &lRespond);
  658.         if (!osErr)
  659.             _osver = lRespond;
  660.  
  661.         return 0;
  662. }
  663.  
  664.  
  665. /***
  666. *exit(status), _exit(status), _cexit(void), _c_exit(void) - C termination
  667. *
  668. *Purpose:
  669. *
  670. *       Entry points:
  671. *
  672. *               exit(code):  Performs all the C termination functions
  673. *                       and terminates the process with the return code
  674. *                       supplied by the user.
  675. *
  676. *               _exit(code):  Performs a quick exit routine that does not
  677. *                       do certain 'high-level' exit processing.  The _exit
  678. *                       routine terminates the process with the return code
  679. *                       supplied by the user.
  680. *
  681. *               _cexit():  Performs the same C lib termination processing
  682. *                       as exit(code) but returns control to the caller
  683. *                       when done (i.e., does NOT terminate the process).
  684. *
  685. *               _c_exit():  Performs the same C lib termination processing
  686. *                       as _exit(code) but returns control to the caller
  687. *                       when done (i.e., does NOT terminate the process).
  688. *
  689. *       Termination actions:
  690. *
  691. *               exit(), _cexit():
  692. *
  693. *               1.      call user's terminator routines
  694. *               2.      call C runtime preterminators
  695. *
  696. *               _exit(), _c_exit():
  697. *
  698. *               3.      call C runtime terminators
  699. *               4.      return to DOS or caller
  700. *
  701. *       Notes:
  702. *
  703. *       The termination sequence is complicated due to the multiple entry
  704. *       points sharing the common code body while having different entry/exit
  705. *       sequences.
  706. *
  707. *       Multi-thread notes:
  708. *
  709. *       1. exit() should NEVER be called when mthread locks are held.
  710. *          The exit() routine can make calls that try to get mthread locks.
  711. *
  712. *       2. _exit()/_c_exit() can be called from anywhere, with or without locks held.
  713. *          Thus, _exit() can NEVER try to get locks (otherwise, deadlock
  714. *          may occur).  _exit() should always 'work' (i.e., the process
  715. *          should always terminate successfully).
  716. *
  717. *       3. Only one thread is allowed into the exit code (see _lockexit()
  718. *          and _unlockexit() routines).
  719. *
  720. *Entry:
  721. *       exit(), _exit()
  722. *               int status - exit status (0-255)
  723. *
  724. *       _cexit(), _c_exit()
  725. *               <no input>
  726. *
  727. *Exit:
  728. *       exit(), _exit()
  729. *               <EXIT to DOS>
  730. *
  731. *       _cexit(), _c_exit()
  732. *               Return to caller
  733. *
  734. *Uses:
  735. *
  736. *Exceptions:
  737. *
  738. *******************************************************************************/
  739.  
  740. /* worker routine prototype */
  741. /* public doexit and make exit and _exit function substitutable */
  742.  
  743. void _CALLTYPE4 doexit (int code, int quick, int retcaller);
  744.  
  745. void _CALLTYPE1 _cexit (
  746.         void
  747.         )
  748. {
  749.         doexit(0, 0, 1);        /* full term, return to caller */
  750. }
  751.  
  752. void _CALLTYPE1 _c_exit (
  753.         void
  754.         )
  755. {
  756.         doexit(0, 1, 1);        /* quick term, return to caller */
  757. }
  758.  
  759.  
  760. void _CALLTYPE4 doexit (
  761.         int code,
  762.         int quick,
  763.         int retcaller
  764.         )
  765. {
  766. #ifdef _MT
  767.         _lockexit();            /* assure only 1 thread in exit path */
  768. #endif  /* _MT */
  769.  
  770.         /* save callable exit flag (for use by terminators) */
  771.         _exitflag = (char) retcaller;  /* 0 = term, !0 = callable exit */
  772.  
  773.         if (!quick) {
  774.  
  775.             /*
  776.              * do _onexit/atexit() terminators
  777.              * (if there are any)
  778.              */
  779.  
  780.             if (__onexitbegin)
  781.                 _initterm(__onexitbegin, __onexitend);
  782.  
  783.             /*
  784.              * do pre-terminators
  785.              */
  786.  
  787.             _initterm(&__xp_a, &__xp_z);
  788.         }
  789.  
  790.         /*
  791.          * do terminators
  792.          */
  793.         _initterm(&__xt_a, &__xt_z);
  794.  
  795.  
  796.         /*
  797.          * Floating point termination should go here...
  798.          */
  799.  
  800. #ifdef _DEBUG
  801.         /* Dump all memory leaks */
  802.         if (_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) & _CRTDBG_LEAK_CHECK_DF)
  803.             _CrtDumpMemoryLeaks();
  804. #endif  /* _DEBUG */
  805.  
  806.         /* return to caller */
  807.         if (retcaller) {
  808. #ifdef _MT
  809.             _unlockexit();      /* unlock the exit code path */
  810. #endif  /* _MT */
  811.             return;
  812.         }
  813.         if (_pMPWBlock != NULL)
  814.             {
  815.             _pMPWBlock->retCode = code;
  816.             }
  817.         _ShellReturn();
  818.  
  819. }
  820.  
  821.  
  822. #ifdef _M_MPPC
  823. void __cdecl _DoExitSpecial(int code, int retcaller,
  824.                             PFV *pAppPreTermBegin, PFV *pAppPreTermEnd,
  825.                             PFV *pAppTermBegin, PFV *pAppTermEnd,
  826.                             PFV *pAppOnexitBeg, PFV *pAppOnexitEnd)
  827.         {
  828. #ifdef _DEBUG
  829.         static int fExit = 0;
  830. #endif  /* _DEBUG */
  831.  
  832.         /*
  833.          * do _onexit/atexit() terminators
  834.          * (if there are any) including C++ destructors
  835.          */
  836.  
  837.         if (pAppOnexitBeg && pAppOnexitBeg != (PFV *)(-1))
  838.             _initterm(pAppOnexitBeg, pAppOnexitEnd);
  839.  
  840.         if (__onexitbegin)
  841.             _initterm(__onexitbegin, __onexitend);
  842.  
  843.         /*
  844.          * do pre-terminators, do app's one first
  845.          */
  846.         _initterm(pAppPreTermBegin, pAppPreTermEnd);
  847.  
  848.         _initterm(&__xp_a, &__xp_z);
  849.  
  850.         /*
  851.          * do terminators, do app's first
  852.          */
  853.         _initterm(pAppTermBegin, pAppTermEnd);
  854.  
  855.         _initterm(&__xt_a, &__xt_z);
  856.  
  857. #ifdef _DEBUG
  858.         /* Dump all memory leaks */
  859.         if (!fExit && _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) & _CRTDBG_LEAK_CHECK_DF)
  860.         {
  861.             fExit = 1;
  862.             _CrtDumpMemoryLeaks();
  863.         }
  864. #endif  /* _DEBUG */
  865.  
  866.         if (_pMPWBlock != NULL)
  867.             {
  868.             _pMPWBlock->retCode = code;
  869.             }
  870.         if (!retcaller)
  871.             {
  872.             _ShellReturn();
  873.             }
  874.         else
  875.             {
  876.             return;
  877.             }
  878.  
  879. }
  880. #endif  /* _M_MPPC */
  881.  
  882.  
  883. #ifdef _MT
  884. /***
  885. * _lockexit - Aquire the exit code lock
  886. *
  887. *Purpose:
  888. *       Makes sure only one thread is in the exit code at a time.
  889. *       If a thread is already in the exit code, it must be allowed
  890. *       to continue.  All other threads must pend.
  891. *
  892. *       Notes:
  893. *
  894. *       (1) It is legal for a thread that already has the lock to
  895. *       try and get it again(!).  That is, consider the following
  896. *       sequence:
  897. *
  898. *               (a) program calls exit()
  899. *               (b) thread locks exit code
  900. *               (c) user onexit() routine calls _exit()
  901. *               (d) same thread tries to lock exit code
  902. *
  903. *       Since _exit() must ALWAYS be able to work (i.e., can be called
  904. *       from anywhere with no regard for locking), we must make sure the
  905. *       program does not deadlock at step (d) above.
  906. *
  907. *       (2) If a thread executing exit() or _exit() aquires the exit lock,
  908. *       other threads trying to get the lock will pend forever.  That is,
  909. *       since exit() and _exit() terminate the process, there is not need
  910. *       for them to unlock the exit code path.
  911. *
  912. *       (3) Note that onexit()/atexit() routines call _lockexit/_unlockexit
  913. *       to protect mthread access to the onexit table.
  914. *
  915. *       (4) The 32-bit semaphore calls DO allow a single thread to aquire the
  916. *       same lock multiple times thus, this version is straight forward.
  917. *
  918. *Entry: <none>
  919. *
  920. *Exit:
  921. *       Calling thread has exit code path locked on return.
  922. *
  923. *Exceptions:
  924. *
  925. *******************************************************************************/
  926.  
  927. void _CALLTYPE1 _lockexit (
  928.         void
  929.         )
  930. {
  931.         _mlock(_EXIT_LOCK1);
  932. }
  933.  
  934. /***
  935. * _unlockexit - Release exit code lock
  936. *
  937. *Purpose:
  938. *       [See _lockexit() description above.]
  939. *
  940. *       This routine is called by _cexit(), _c_exit(), and onexit()/atexit().
  941. *       The exit() and _exit() routines never unlock the exit code path since
  942. *       they are terminating the process.
  943. *
  944. *Entry:
  945. *       Exit code path is unlocked.
  946. *
  947. *Exit:
  948. *
  949. *Exceptions:
  950. *
  951. *******************************************************************************/
  952.  
  953. void _CALLTYPE1 _unlockexit (
  954.         void
  955.         )
  956. {
  957.         _munlock(_EXIT_LOCK1);
  958. }
  959.  
  960. #endif  /* _MT */
  961.  
  962. /***
  963. * static void _initterm(PFV * pfbegin, PFV * pfend) - call entries in
  964. *       function pointer table
  965. *
  966. *Purpose:
  967. *       Walk a table of function pointers, calling each entry, as follows:
  968. *
  969. *               1. walk from beginning to end, pfunctbl is assumed to point
  970. *                  to the beginning of the table, which is currently a null entry,
  971. *                  as is the end entry.
  972. *               2. skip NULL entries
  973. *               3. stop walking when the end of the table is encountered
  974. *
  975. *Entry:
  976. *       PFV *pfbegin    - pointer to the beginning of the table (first valid entry).
  977. *       PFV *pfend      - pointer to the end of the table (after last valid entry).
  978. *
  979. *Exit:
  980. *       No return value
  981. *
  982. *Notes:
  983. *       For onexit() to work, this routine must start with the entry pointed
  984. *       to by pfbegin and must stop before trying to call what pfend points
  985. *       to.  __onexitbegin points to a valid entry but __onexitend does not!
  986. *
  987. *Exceptions:
  988. *       If either pfbegin or pfend is NULL, or invalid, all bets are off!
  989. *
  990. *******************************************************************************/
  991. #ifndef _M_MPPC
  992. static void _CALLTYPE4 _initterm (
  993.         PFV * pfbegin,
  994.         PFV * pfend
  995.         )
  996. #else  /* _M_MPPC */
  997. void _CALLTYPE4 _initterm (
  998.         PFV * pfbegin,
  999.         PFV * pfend
  1000.         )
  1001. #endif  /* _M_MPPC */
  1002. {
  1003.         /*
  1004.          * walk the table of function pointers from the top down, until
  1005.          * bottom is encountered.  Do not skip the first entry.
  1006.          */
  1007.         for ( ;pfbegin < pfend ; pfbegin++)
  1008.         {
  1009.             /*
  1010.              * if current table entry is non-NULL (and not -1), call
  1011.              * thru it from end of table to begin.
  1012.              */
  1013.             if ( *pfbegin != NULL && *pfbegin != (PFV) -1 )
  1014.                 (**pfbegin)();
  1015.         }
  1016. }
  1017.  
  1018. #endif  /* _WIN32 */
  1019.  
  1020.