Windows2000/private/shell/iert/crt0dat.c

430 lines
10 KiB
C

/*
*crt0dat.c - 32-bit C run-time initialization/termination routines
* Copyright (c) 1986-1995, Microsoft Corporation. All rights reserved.
*Purpose:
* This module contains the routines _cinit, exit, and _exit
* for C run-time startup and termination.
* This file is a modified version for use with Forms3 that removes most
* of the C run-time startup code for improved performance.
*/
typedef void (__cdecl *_PVFV)(void);
#include "windows.h"
#include "excpt.h"
// The compiler generates references to this variable when you use floating
// point, so we need it here.
int _fltused = 0x9875;
int __fastflag = 0;
int _adjust_fdiv = 0;
int _ldused = 0x9873;
int _iob;
char _osfile[20];
int errno;
CRITICAL_SECTION s_cs;
int errno1 = 0;
int __error_mode; // error_mode and _apptype, together, determine how error messages are written out.
int __app_type;
#if DBG == 1
void lock_cleanup(void);
#endif
void BreakHere();
int * _cdecl _errno(void)
{
return &errno1;
}
#define errno (*_errno())
extern int _cpvfv;
extern _PVFV * _apvfv;
void __cdecl _cinit (void);
void __cdecl _cexit (void);
// common globals used by console and gui exe support.
//command line, environment, and a few other globals
char *_acmdln; /* points to command line */
char *_aenvptr; /* points to environment block */
wchar_t *_wenvptr; /* points to wide environment block */
int _umaskval = 0; // define umask
/* define version info variables */
_CRTIMP unsigned int _osver = 0;
_CRTIMP unsigned int _winver = 0;
_CRTIMP unsigned int _winmajor = 0;
_CRTIMP unsigned int _winminor = 0;
/* argument vector and environment */
_CRTIMP int __argc = 0;
_CRTIMP char **__argv = NULL;
_CRTIMP wchar_t **__wargv = NULL;
_CRTIMP char **_environ = NULL;
_CRTIMP char **__initenv = NULL;
_CRTIMP wchar_t **_wenviron = NULL;
_CRTIMP wchar_t **__winitenv = NULL;
_CRTIMP char *_pgmptr = NULL; /* ptr to program name */
_CRTIMP wchar_t *_wpgmptr = NULL; /* ptr to wide program name */
char _exitflag = 0; // callable exit flag
// end common globals used by console and gui exe support.
/*
* flag indicating if C runtime termination has been done. set if exit,
* _exit, _cexit or _c_exit has been called. checked when _CRTDLL_INIT
* is called with DLL_PROCESS_DETACH.
*/
int _C_Termination_Done = FALSE;
int _C_Exit_Done = FALSE;
/*
* 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 sections
*/
#if defined(_M_IA64)
#pragma section(".CRT$XIA",long,read)
#pragma section(".CRT$XIZ",long,read)
#pragma section(".CRT$XCA",long,read)
#pragma section(".CRT$XCZ",long,read)
#pragma section(".CRT$XPA",long,read)
#pragma section(".CRT$XPZ",long,read)
#pragma section(".CRT$XTA",long,read)
#pragma section(".CRT$XTZ",long,read)
__declspec(allocate(".CRT$XIA")) _PVFV __xi_a[] = { NULL };
__declspec(allocate(".CRT$XIZ")) _PVFV __xi_z[] = { NULL };
__declspec(allocate(".CRT$XCA")) _PVFV __xc_a[] = { NULL };
__declspec(allocate(".CRT$XCZ")) _PVFV __xc_z[] = { NULL };
__declspec(allocate(".CRT$XPA")) _PVFV __xp_a[] = { NULL };
__declspec(allocate(".CRT$XPZ")) _PVFV __xp_z[] = { NULL };
__declspec(allocate(".CRT$XTA")) _PVFV __xt_a[] = { NULL };
__declspec(allocate(".CRT$XTZ")) _PVFV __xt_z[] = { NULL };
#pragma comment(linker, "/merge:.CRT=.rdata")
#else
#pragma data_seg(".CRT$XIA")
_PVFV __xi_a[] = { NULL };
#pragma data_seg(".CRT$XIZ")
_PVFV __xi_z[] = { NULL };
#pragma data_seg(".CRT$XCA")
_PVFV __xc_a[] = { NULL };
#pragma data_seg(".CRT$XCZ")
_PVFV __xc_z[] = { NULL };
#pragma data_seg(".CRT$XPA")
_PVFV __xp_a[] = { NULL };
#pragma data_seg(".CRT$XPZ")
_PVFV __xp_z[] = { NULL };
#pragma data_seg(".CRT$XTA")
_PVFV __xt_a[] = { NULL };
#pragma data_seg(".CRT$XTZ")
_PVFV __xt_z[] = { NULL };
#pragma data_seg() /* reset */
#pragma comment(linker, "-merge:.CRT=.data")
#endif
/*
* 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
*/
static void __cdecl _initterm(_PVFV *, _PVFV *);
/*
*_cinit - C initialization -- modified Forms3 version
*Purpose:
* Calls C and C++ initializer routines
*Entry:
* No parameters: Called from __crtstart and assumes data
* set up correctly there.
*Exit:
* Initializes C runtime data.
*Exceptions:
*/
void __cdecl _cinit (
void
)
{
/*
* do initializations
*/
_initterm( __xi_a, __xi_z );
/*
* do C++ initializations
*/
_initterm( __xc_a, __xc_z );
}
/*
*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 __cdecl doexit (int code, int quick, int retcaller);
void __cdecl exit (
int code
)
{
doexit(code, 0, 0); /* full term, kill process */
}
void __cdecl _exit (
int code
)
{
doexit(code, 1, 0); /* quick term, kill process */
}
void __cdecl _cexit (
void
)
{
doexit(0, 0, 1); /* full term, return to caller */
}
void __cdecl _c_exit (
void
)
{
doexit(0, 1, 1); /* quick term, return to caller */
}
void (__cdecl * _aexit_rtn)(int) = _exit; /* RT message return procedure */
static void __cdecl doexit (
int code,
int quick,
int retcaller
)
{
EnterCriticalSection(&s_cs);
if (_C_Exit_Done == TRUE) /* if doexit() is being called recursively */
TerminateProcess(GetCurrentProcess(),code); /* terminate with extreme prejudice */
_C_Termination_Done = TRUE;
/* save callable exit flag (for use by terminators) */
if (!quick)
{
/*
* do atexit() terminators
* (if there are any)
* These terminators MUST be executed in reverse order (LIFO)!
*/
if (_cpvfv > 0)
{
_PVFV *ppfunc;
int i;
for (i=_cpvfv, ppfunc=_apvfv + i - 1; i > 0; i--, ppfunc--)
{
if (*ppfunc)
(*ppfunc)();
}
LocalFree(_apvfv);
_cpvfv = 0;
}
/* do pre-terminators */
_initterm(__xp_a, __xp_z);
}
/* do terminators */
_initterm(__xt_a, __xt_z);
/* return to OS or to caller */
if (retcaller)
{
LeaveCriticalSection(&s_cs);
return;
}
_C_Exit_Done = TRUE;
ExitProcess(code);
}
/*
* static void _initterm(_PVFV * pfbegin, _PVFV * 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:
* _PVFV *pfbegin - pointer to the beginning of the table (first valid entry).
* _PVFV *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!
*/
static void __cdecl _initterm (
_PVFV * pfbegin,
_PVFV * 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;
}
}
void __cdecl terminate()
{
BreakHere();
ExitProcess(1);
}
void __cdecl _amsg_exit( int ret )
{
BreakHere();
exit(ret);
}