summaryrefslogtreecommitdiffstats
path: root/private/crt32/startup/crt0dat.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/crt32/startup/crt0dat.c')
-rw-r--r--private/crt32/startup/crt0dat.c794
1 files changed, 794 insertions, 0 deletions
diff --git a/private/crt32/startup/crt0dat.c b/private/crt32/startup/crt0dat.c
new file mode 100644
index 000000000..42b6854bc
--- /dev/null
+++ b/private/crt32/startup/crt0dat.c
@@ -0,0 +1,794 @@
+/***
+*crt0dat.c - 32-bit C run-time initialization/termination routines
+*
+* Copyright (c) 1986-1992, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This module contains the routines _cinit, exit, and _exit
+* for C run-time startup and termination. _cinit and exit
+* are called from the _astart code in crt0.asm.
+* This module also defines several data variables used by the
+* runtime.
+*
+* [NOTE: Lock segment definitions are at end of module.]
+*
+* *** FLOATING POINT INITIALIZATION AND TERMINATION ARE NOT ***
+* *** YET IMPLEMENTED IN THIS FILE ***
+*
+*Revision History:
+* 06-28-89 PHG Module created, based on asm version
+* 04-09-90 GJF Added #include <cruntime.h>. Made calling type
+* explicit (_CALLTYPE1 or _CALLTYPE4). Also, fixed
+* the copyright.
+* 04-10-90 GJF Fixed compiler warnings (-W3).
+* 05-21-90 GJF Added #undef _NFILE_ (temporary hack) and fixed the
+* indents.
+* 08-31-90 GJF Removed 32 from API names.
+* 09-25-90 GJF Merged tree version with local (8-31 and 5-21 changes).
+* 10-08-90 GJF New-style function declarators.
+* 10-12-90 GJF Removed divide by 0 stuff.
+* 10-18-90 GJF Added _pipech[] array.
+* 11-05-90 GJF Added _umaskval.
+* 12-04-90 GJF Added _osfinfo[] definition for Win32 target. Note that
+* the Win32 support is still incomplete!
+* 12-04-90 SRW Changed to include <oscalls.h> instead of <doscalls.h>
+* 12-04-90 SRW Added _osfile back for win32. Changed _osfinfo from
+* an array of structures to an array of 32-bit handles
+* (_osfhnd)
+* 12-28-90 SRW Added _CRUISER_ conditional around pack pragmas
+* 01-29-91 GJF ANSI naming.
+* 01-29-91 SRW Added call to GetFileType [_WIN32_]
+* 02-18-91 SRW Removed duplicate defintion of _NFILE_ (see os2dll.h)
+* 04-04-91 GJF Added definitions for _base[version|major|minor]
+* (_WIN32_).
+* 04-08-91 GJF Temporary hack for Win32/DOS folks - added HeapDestroy
+* call to doexit to tear down the OS heap used by C
+* heap.
+* 04-09-91 PNT Added _MAC_ conditional
+* 04-26-91 SRW Removed level 3 warnings
+* 07-16-91 GJF Added fp initialization test-and-call [_WIN32_].
+* 07-26-91 GJF Revised initialization and termination stuff. In
+* particular, removed need for win32ini.c [_WIN32_].
+* 08-07-91 GJF Added init. for FORTRAN runtime, if present [_WIN32_].
+* 08-21-91 GJF Test _prmtmp against NULL, not _prmtmp().
+* 08-21-91 JCR Added _exitflag, _endstdio, _cpumode, etc.
+* 09-09-91 GJF Revised _doinitterm for C++ init. support and to make
+* _onexit/atexit compatible with C++ needs.
+* 09-16-91 GJF Must test __onexitend before calling _doinitterm.
+* 10-29-91 GJF Force in floating point initialization for MIPS
+* compiler [_WIN32_].
+* 11-13-91 GJF FORTRAN needs _onexit/atexit init. before call thru
+* _pFFinit.
+* 01-10-92 GJF Merged. Also, added _C_Termination_Done [_WIN32_].
+* 02-13-92 GJF Moved all lowio initialization to ioinit.c for Win32.
+* 03-12-92 SKS Major changes to initialization/termination scheme
+* 04-16-92 DJM POSIX support.
+* 04-17-92 SKS Export _initterm() for CRTDLL model
+* 05-07-92 DJM Removed _exit() from POSIX build.
+* 06-03-92 GJF Temporarily restored call to FORTRAN init.
+* 08-26-92 SKS Add _osver, _winver, _winmajor, _winminor
+* 08-28-92 GJF Use unistd.h for POSIX build.
+* 09-02-92 SKS Fix _onexit table traversal to be LIFO.
+* Since table is built forward (my changes 03-12-92)
+* the table must be traversed in reverse order.
+* 10-30-92 TVB Force in floating point initialization for ALPHA
+* compiler as was done for MIPS. [_WIN32_].
+* 11-12-92 SKS Remove hard-coded call to FORTRAN initializer
+* 05-11-93 SKS _C_Termination_Done is now used by DLLs in LIBC/LIBCMT
+* models, not just in CRTDLL.DLL.
+* Remove obsolete variable _child.
+* 07-16-93 SRW ALPHA Merge
+*
+*******************************************************************************/
+
+#include <cruntime.h>
+#ifdef _POSIX_
+#include <unistd.h>
+#else
+#include <msdos.h>
+#endif
+#include <dos.h>
+#include <oscalls.h>
+#include <os2dll.h>
+#include <internal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <process.h>
+
+/* define errno */
+#ifndef MTHREAD
+int _VARTYPE1 errno = 0; /* libc error value */
+#ifdef _CRUISER_
+int _VARTYPE1 _doserrno = 0; /* OS system error value */
+#else /* ndef _CRUISER_ */
+#ifdef _WIN32_
+unsigned long _VARTYPE1 _doserrno = 0; /* OS system error value */
+#endif /* _WIN32_ */
+#endif /* _CRUISER_ */
+#endif /* MTHREAD */
+
+/* define umask */
+int _umaskval = 0;
+
+/* define version info variables */
+
+unsigned int _VARTYPE1 _osver = 0;
+unsigned int _VARTYPE1 _winver = 0;
+unsigned int _VARTYPE1 _winmajor = 0;
+unsigned int _VARTYPE1 _winminor = 0;
+
+/* --------- The following block is OBSOLETE --------- */
+
+unsigned int _VARTYPE1 _osversion = 0;
+unsigned int _VARTYPE1 _osmajor = 0;
+unsigned int _VARTYPE1 _osminor = 0;
+
+#if defined(_WIN32_) || defined(_POSIX_)
+unsigned int _VARTYPE1 _baseversion = 0;
+unsigned int _VARTYPE1 _basemajor = 0;
+unsigned int _VARTYPE1 _baseminor = 0;
+#endif /* _WIN32_ || _POSIX_ */
+
+/* define _osmode/_cpumode */
+
+#ifdef _CRUISER_
+unsigned char _osmode = _OS2_20_MODE;
+#else /* ndef _CRUISER_ */
+#ifdef _DOSX32_
+unsigned char _osmode = _DOSX32_MODE;
+#else /* ndef _DOSX32_ */
+#ifdef _WIN32_
+unsigned char _osmode = _WIN_MODE;
+#else /* ndef _WIN32_ */
+#ifdef _POSIX_
+unsigned char _osmode = _POSIX_MODE_;
+#endif /* _POSIX_ */
+#endif /* _WIN32DOS_ */
+#endif /* _WIN32_ */
+#endif /* _CRUISER_ */
+
+unsigned char _cpumode = _FLAT_MODE;
+
+/* --------- The preceding block is OBSOLETE --------- */
+
+#ifdef _CRUISER_
+
+/* number of allowable file handles */
+int _nfile = _NFILE_;
+
+/* file handle database -- stdout, stdin, stderr are open */
+char _osfile[_NFILE_] = {FOPEN+FTEXT, FOPEN+FTEXT, FOPEN+FTEXT};
+
+#endif /* _CRUISER_ */
+
+#ifdef _WIN32DOS_
+extern HANDLE _HeapHandle;
+#endif /* _WIN32DOS_ */
+
+#ifdef _CRUISER_
+
+/* peek-ahead buffers for pipes, each initialized to a newline */
+
+char _pipech[_NFILE_] = {
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10
+#ifdef MTHREAD
+ , 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10
+#endif
+ };
+#endif /* _CRUISER_ */
+
+/* argument vector and environment */
+int __argc = 0;
+char **__argv = NULL;
+#ifdef _POSIX_
+char **environ = NULL;
+#else
+char **_environ = NULL;
+#endif
+char *_pgmptr; /* ptr to program name */
+
+/* callable exit flag */
+char _exitflag = 0;
+
+#if defined(_WIN32_)
+/*
+ * flag indicating if C runtime termination has been done. set if exit,
+ * _exit, _cexit or _c_exit has been called. checked when _CRTDLL_INIT
+ * or user DLL's _CRT_INIT is called with DLL_PROCESS_DETACH.
+ */
+int _C_Termination_Done = FALSE;
+#endif
+
+/*
+ * useful type for initialization and termination declarations
+ */
+typedef void (_CALLTYPE1 *PF)(void);
+
+#ifdef _CRUISER_
+
+PF *__onexittable = NULL; /* ptr to on exit function table */
+
+#else /* ndef _CRUISER_ */
+
+#if defined(_WIN32_) || defined(_POSIX_)
+
+/*
+ * NOTE: THE USE OF THE POINTERS DECLARED BELOW DEPENDS ON THE PROPERTIES
+ * OF C COMMUNAL VARIABLES. SPECIFICALLY, THEY ARE NON-NULL IFF THERE EXISTS
+ * A DEFINITION ELSEWHERE INITIALIZING THEM TO NON-NULL VALUES.
+ */
+
+/*
+ * pointers to initialization functions
+ */
+
+PF _FPinit; /* floating point init. */
+
+/*
+ * pointers to initialization sections
+ */
+
+extern PF __xi_a[], __xi_z[]; /* C initializers */
+extern PF __xc_a[], __xc_z[]; /* C++ initializers */
+extern PF __xp_a[], __xp_z[]; /* C pre-terminators */
+extern PF __xt_a[], __xt_z[]; /* C terminators */
+
+#if defined(_M_MRX000) || defined(_M_ALPHA) || defined(_M_PPC)
+/*
+ * For MIPS or ALPHA compilers, must explicitly force in and call the floating
+ * point initialization (those system always have floating-point hardware).
+ */
+extern void _CALLTYPE1 _fpmath(void);
+#endif
+
+/*
+ * pointers to the start and finish of the _onexit/atexit table
+ */
+PF *__onexitbegin;
+PF *__onexitend;
+
+
+/*
+ * static (internal) function that walks a table of function pointers,
+ * calling each entry between the two pointers, skipping NULL entries
+ *
+ * Needs to be exported for CRT DLL so that C++ initializers in the
+ * client EXE / DLLs can be initialized
+ */
+#ifdef CRTDLL
+void _CALLTYPE1 _initterm(PF *, PF *);
+#else
+static void _CALLTYPE4 _initterm(PF *, PF *);
+#endif
+
+#else /* ndef _WIN32_ || _POSIX_ */
+
+#error ERROR - ONLY CRUISER, WIN32, OR POSIX TARGET SUPPORTED!
+
+#endif /* _WIN32_ || _POSIX_ */
+
+#endif /* _CRUISER_ */
+
+
+/***
+*_cinit - C initialization
+*
+*Purpose:
+* This routine performs the shared DOS and Windows initialization.
+* The following order of initialization must be preserved -
+*
+ifdef MTHREAD
+* 0. Call OS2 to bump max file count (mthread only)
+endif
+* 1. Check for devices for file handles 0 - 2
+* 2. Integer divide interrupt vector setup
+* 3. General C initializer routines
+*
+*Entry:
+* No parameters: Called from __crtstart and assumes data
+* set up correctly there.
+*
+*Exit:
+* Initializes C runtime data.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void _CALLTYPE1 _cinit (
+ void
+ )
+{
+#ifdef _CRUISER_
+ int fh; /* file handle we're checking */
+ ULONG htype; /* handle type */
+
+#ifdef MTHREAD
+ /* 0. Call OS/2 to bump max file count --
+ even though the IO database supports _NFILE_ (256) files,
+ only bump the count to _NFILE_MAXFH_ (40) */
+
+ DOSSETMAXFH(_NFILE_MAXFH_);
+#else
+ #if 0
+ /* This code is intentionally commented out -- to access more
+ than 20 files re-enable this code */
+ DOSSETMAXFH(_NFILE_);
+ #endif
+#endif
+
+ /* 1. check for devices on file handles 0 - 2 */
+ for (fh = 0; fh <= 2; ++fh) {
+ ULONG devattr; /* device attributes */
+
+ /* default: neither pipe nor device */
+ _osfile[fh] &= ~(FDEV | FPIPE);
+
+ if (DOSQUERYHTYPE(fh, &htype, &devattr) == 0) {
+ /* check returned handle type -- only lo byte */
+ if ((htype & 0xFF) == HANDTYPE_DEVICE)
+ _osfile[fh] |= FDEV;
+ else if ((htype & 0xFF) == HANDTYPE_PIPE)
+ _osfile[fh] |= FPIPE;
+ }
+ }
+
+ /* 2. general C initializer routines */
+
+/******* FLOATING POINT INIT SHOULD GO HERE (before initclock) ******/
+
+ __doinits(); /* execute initializers */
+
+#else /* ndef _CRUISER_ */
+
+#if defined(_WIN32_) || defined(_POSIX_)
+ /*
+ * initialize floating point package, if present
+ */
+#if defined(_M_MRX000) || defined(_M_ALPHA) || defined(_M_PPC)
+ /*
+ * The Mips, Alpha, and PPC compilers don't emit external reference to
+ * _fltused. Therefore, must always force in the floating point
+ * initialization.
+ */
+ _fpmath();
+#else
+ if ( _FPinit != NULL )
+ (*_FPinit)();
+#endif
+
+ /*
+ * do initializations
+ */
+ _initterm( __xi_a, __xi_z );
+
+ /*
+ * do C++ initializations
+ */
+ _initterm( __xc_a, __xc_z );
+
+#else /* ndef _WIN32_ || _POSIX_ */
+
+#ifdef _MAC_
+
+ TBD();
+
+#else /* ndef _MAC_ */
+
+#error ERROR - ONLY CRUISER, WIN32, MAC, OR POSIX TARGET SUPPORTED!
+
+#endif /* _MAC_ */
+
+#endif /* _WIN32_ */
+
+#endif /* _CRUISER_ */
+
+}
+
+
+/***
+*exit(status), _exit(status), _cexit(void), _c_exit(void) - C termination
+*
+*Purpose:
+*
+* Entry points:
+*
+* exit(code): Performs all the C termination functions
+* and terminates the process with the return code
+* supplied by the user.
+*
+* _exit(code): Performs a quick exit routine that does not
+* do certain 'high-level' exit processing. The _exit
+* routine terminates the process with the return code
+* supplied by the user.
+*
+* _cexit(): Performs the same C lib termination processing
+* as exit(code) but returns control to the caller
+* when done (i.e., does NOT terminate the process).
+*
+* _c_exit(): Performs the same C lib termination processing
+* as _exit(code) but returns control to the caller
+* when done (i.e., does NOT terminate the process).
+*
+* Termination actions:
+*
+* exit(), _cexit():
+*
+* 1. call user's terminator routines
+* 2. call C runtime preterminators
+*
+* _exit(), _c_exit():
+*
+* 3. call C runtime terminators
+* 4. return to DOS or caller
+*
+* Notes:
+*
+* The termination sequence is complicated due to the multiple entry
+* points sharing the common code body while having different entry/exit
+* sequences.
+*
+* Multi-thread notes:
+*
+* 1. exit() should NEVER be called when mthread locks are held.
+* The exit() routine can make calls that try to get mthread locks.
+*
+* 2. _exit()/_c_exit() can be called from anywhere, with or without locks held.
+* Thus, _exit() can NEVER try to get locks (otherwise, deadlock
+* may occur). _exit() should always 'work' (i.e., the process
+* should always terminate successfully).
+*
+* 3. Only one thread is allowed into the exit code (see _lockexit()
+* and _unlockexit() routines).
+*
+*Entry:
+* exit(), _exit()
+* int status - exit status (0-255)
+*
+* _cexit(), _c_exit()
+* <no input>
+*
+*Exit:
+* exit(), _exit()
+* <EXIT to DOS>
+*
+* _cexit(), _c_exit()
+* Return to caller
+*
+*Uses:
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+/* worker routine prototype */
+static void _CALLTYPE4 doexit (int code, int quick, int retcaller);
+
+void _CALLTYPE1 exit (
+ int code
+ )
+{
+ doexit(code, 0, 0); /* full term, kill process */
+}
+
+#ifndef _POSIX_
+
+void _CALLTYPE1 _exit (
+ int code
+ )
+{
+ doexit(code, 1, 0); /* quick term, kill process */
+}
+
+void _CALLTYPE1 _cexit (
+ void
+ )
+{
+ doexit(0, 0, 1); /* full term, return to caller */
+}
+
+void _CALLTYPE1 _c_exit (
+ void
+ )
+{
+ doexit(0, 1, 1); /* quick term, return to caller */
+}
+
+#endif /* _POSIX_ */
+
+
+static void _CALLTYPE4 doexit (
+ int code,
+ int quick,
+ int retcaller
+ )
+{
+#ifdef MTHREAD
+ _lockexit(); /* assure only 1 thread in exit path */
+#endif
+
+#if defined(_WIN32_) && defined(CRTDLL)
+ _C_Termination_Done = TRUE;
+#endif
+
+ /* save callable exit flag (for use by terminators) */
+ _exitflag = (char) retcaller; /* 0 = term, !0 = callable exit */
+
+ if (!quick) {
+
+#ifdef _CRUISER_
+ /*
+ * do _onexit/atexit() terminators
+ */
+ if ( __onexitend != NULL )
+ _doinitterm(__onexitend);
+
+ /* call pre-terminators (flushall, rmtmp) */
+ __dopreterms();
+ }
+
+ /* do C terminators */
+ __doterms();
+
+#else /* ndef _CRUISER_ */
+
+#if defined(_WIN32_) || defined(_POSIX_)
+ /*
+ * do _onexit/atexit() terminators
+ * (if there are any)
+ *
+ * These terminators MUST be executed in reverse order (LIFO)!
+ *
+ * NOTE:
+ * This code assumes that __onexitbegin points
+ * to the first valid onexit() entry and that
+ * __onexitend points past the last valid entry.
+ * If __onexitbegin == __onexitend, the table
+ * is empty and there are no routines to call.
+ */
+
+ if (__onexitbegin) {
+ PF * pfend = __onexitend;
+
+ while ( -- pfend >= __onexitbegin )
+ /*
+ * if current table entry is non-NULL,
+ * call thru it.
+ */
+ if ( *pfend != NULL )
+ (**pfend)();
+ }
+
+ /*
+ * do pre-terminators
+ */
+ _initterm(__xp_a, __xp_z);
+ }
+
+ /*
+ * do terminators
+ */
+ _initterm(__xt_a, __xt_z);
+
+#else /* ndef _WIN32_ || _POSIX_ */
+
+#error ERROR - ONLY CRUISER, WIN32, OR POSIX TARGET SUPPORTED!
+
+#endif /* _WIN32_ || _POSIX_ */
+
+#endif /* _CRUISER_ */
+
+
+#ifdef _WIN32DOS_
+
+/*
+ * TEMPORARY HACK! THE CODE BELOW IS INTENDED TO ALLOW LIMITED USE OF THE
+ * C RUNTIME ON WIN32/DOS. IT WILL BE DELETED AS SOON AS THEY IMPLEMENT
+ * VirtualAlloc()!
+ */
+
+ HeapDestroy(_HeapHandle);
+
+#endif /* _WIN32DOS_ */
+
+
+/********** FLOATING POINT TERMINATION SHOULD GO HERE ************/
+
+ /* return to OS/2 or to caller */
+ if (retcaller) {
+#ifdef MTHREAD
+ _unlockexit(); /* unlock the exit code path */
+#endif
+ return;
+ }
+
+#ifdef _CRUISER_
+
+ DOSEXIT(EXIT_PROCESS, code);
+
+#else /* ndef _CRUISER_ */
+
+#ifdef _WIN32_
+
+ ExitProcess(code);
+
+#else /* ndef _WIN32_ */
+
+#ifdef _POSIX_
+
+ _exit(code);
+
+#else /* ndef _POSIX_ */
+
+#ifdef _MAC_
+
+ TBD();
+
+#else /* ndef _MAC_ */
+
+#error ERROR - ONLY CRUISER, WIN32, MAC, OR POSIX TARGET SUPPORTED!
+
+#endif /* _POSIX_ */
+
+#endif /* _MAC_ */
+
+#endif /* _WIN32_ */
+
+#endif /* _CRUISER_ */
+}
+
+#ifdef MTHREAD
+/***
+* _lockexit - Aquire the exit code lock
+*
+*Purpose:
+* Makes sure only one thread is in the exit code at a time.
+* If a thread is already in the exit code, it must be allowed
+* to continue. All other threads must pend.
+*
+* Notes:
+*
+* (1) It is legal for a thread that already has the lock to
+* try and get it again(!). That is, consider the following
+* sequence:
+*
+* (a) program calls exit()
+* (b) thread locks exit code
+* (c) user onexit() routine calls _exit()
+* (d) same thread tries to lock exit code
+*
+* Since _exit() must ALWAYS be able to work (i.e., can be called
+* from anywhere with no regard for locking), we must make sure the
+* program does not deadlock at step (d) above.
+*
+* (2) If a thread executing exit() or _exit() aquires the exit lock,
+* other threads trying to get the lock will pend forever. That is,
+* since exit() and _exit() terminate the process, there is not need
+* for them to unlock the exit code path.
+*
+* (3) Note that onexit()/atexit() routines call _lockexit/_unlockexit
+* to protect mthread access to the onexit table.
+*
+* (4) The _lockexit/_unlockexit routines are very complicated in 286
+* OS/2 since a thread that held a lock could not request the lock again.
+* The 32-bit OS/2 semaphore calls DO allow a single thread to aquire the
+* same lock multiple times* thus, this version is straight forward.
+*
+*Entry: <none>
+*
+*Exit:
+* Calling thread has exit code path locked on return.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void _CALLTYPE1 _lockexit (
+ void
+ )
+{
+ _mlock(_EXIT_LOCK1);
+}
+
+/***
+* _unlockexit - Release exit code lock
+*
+*Purpose:
+* [See _lockexit() description above.]
+*
+* This routine is called by _cexit(), _c_exit(), and onexit()/atexit().
+* The exit() and _exit() routines never unlock the exit code path since
+* they are terminating the process.
+*
+*Entry:
+* Exit code path is unlocked.
+*
+*Exit:
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void _CALLTYPE1 _unlockexit (
+ void
+ )
+{
+ _munlock(_EXIT_LOCK1);
+}
+
+#endif /* MTHREAD */
+
+
+#if defined(_WIN32_) || defined(_POSIX_)
+
+/***
+* static void _initterm(PF * pfbegin, PF * pfend) - call entries in
+* function pointer table
+*
+*Purpose:
+* Walk a table of function pointers, calling each entry, as follows:
+*
+* 1. walk from beginning to end, pfunctbl is assumed to point
+* to the beginning of the table, which is currently a null entry,
+* as is the end entry.
+* 2. skip NULL entries
+* 3. stop walking when the end of the table is encountered
+*
+*Entry:
+* PF *pfbegin - pointer to the beginning of the table (first valid entry).
+* PF *pfend - pointer to the end of the table (after last valid entry).
+*
+*Exit:
+* No return value
+*
+*Notes:
+* This routine must be exported in the CRT DLL model so that the client
+* EXE and client DLL(s) can call it to initialize their C++ constructors.
+*
+*Exceptions:
+* If either pfbegin or pfend is NULL, or invalid, all bets are off!
+*
+*******************************************************************************/
+
+#ifdef CRTDLL
+void _CALLTYPE1 _initterm (
+#else
+static void _CALLTYPE4 _initterm (
+#endif
+ PF * pfbegin,
+ PF * pfend
+ )
+{
+ /*
+ * walk the table of function pointers from the bottom up, until
+ * the end is encountered. Do not skip the first entry. The initial
+ * value of pfbegin points to the first valid entry. Do not try to
+ * execute what pfend points to. Only entries before pfend are valid.
+ */
+ while ( pfbegin < pfend )
+ {
+ /*
+ * if current table entry is non-NULL, call thru it.
+ */
+ if ( *pfbegin != NULL )
+ (**pfbegin)();
+ ++pfbegin;
+ }
+}
+
+#endif /* _WIN32_ || _POSIX_ */