Removes WInit module completely. Refs #2611
Comments By: phosit Differential Revision: https://code.wildfiregames.com/D5085 This was SVN commit r27810.
This commit is contained in:
parent
11e8f80b58
commit
82bf9bb902
@ -1076,9 +1076,6 @@ function setup_main_exe ()
|
||||
linkoptions {
|
||||
-- wraps main thread in a __try block(see wseh.cpp). replace with mainCRTStartup if that's undesired.
|
||||
"/ENTRY:wseh_EntryPoint",
|
||||
|
||||
-- see wstartup.h
|
||||
"/INCLUDE:_wstartup_InitAndRegisterShutdown",
|
||||
}
|
||||
|
||||
links { "delayimp" }
|
||||
@ -1479,8 +1476,6 @@ function setup_tests()
|
||||
-- from "lowlevel" static lib; must be added here to be linked in
|
||||
files { source_root.."lib/sysdep/os/win/error_dialog.rc" }
|
||||
|
||||
-- see wstartup.h
|
||||
linkoptions { "/INCLUDE:_wstartup_InitAndRegisterShutdown" }
|
||||
-- Enables console for the TEST project on Windows
|
||||
linkoptions { "/SUBSYSTEM:CONSOLE" }
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2023 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
@ -30,15 +30,10 @@
|
||||
#include "lib/allocators/shared_ptr.h"
|
||||
#include "lib/path.h" // path_is_subpath
|
||||
#include "lib/sysdep/os/win/win.h"
|
||||
#include "lib/sysdep/os/win/winit.h"
|
||||
#include "lib/sysdep/os/win/wutil.h"
|
||||
#include "lib/sysdep/os/win/wiocp.h"
|
||||
|
||||
|
||||
WINIT_REGISTER_MAIN_INIT(wdir_watch_Init);
|
||||
WINIT_REGISTER_MAIN_SHUTDOWN(wdir_watch_Shutdown);
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// DirHandle
|
||||
|
||||
@ -370,13 +365,13 @@ Status dir_watch_Poll(DirWatchNotifications& notifications)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static Status wdir_watch_Init()
|
||||
Status wdir_watch_Init()
|
||||
{
|
||||
s_dirWatchManager = new DirWatchManager;
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
static Status wdir_watch_Shutdown()
|
||||
Status wdir_watch_Shutdown()
|
||||
{
|
||||
SAFE_DELETE(s_dirWatchManager);
|
||||
return INFO::OK;
|
||||
|
@ -1,95 +0,0 @@
|
||||
/* Copyright (C) 2010 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* windows-specific module init and shutdown mechanism
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
#include "lib/sysdep/os/win/winit.h"
|
||||
|
||||
#include "lib/sysdep/os/win/win.h" // GetTickCount for quick'n dirty timing
|
||||
|
||||
// see http://blogs.msdn.com/larryosterman/archive/2004/09/27/234840.aspx
|
||||
// for discussion of a similar mechanism.
|
||||
//
|
||||
// note: this module is kept distinct from the CRT's init/shutdown mechanism
|
||||
// to insulate against changes there. another advantage is that callbacks
|
||||
// can return Status instead of int.
|
||||
|
||||
// currently (2008-02-17) the init groups are populated as follows:
|
||||
// critical : wposix
|
||||
// early : wutil
|
||||
// early2 : whrt, wdbg_heap
|
||||
// main : waio, wsock, wtime, wdir_watch
|
||||
// late : wsdl
|
||||
|
||||
typedef Status (*PfnLibError)();
|
||||
|
||||
// pointers to start and end of function tables.
|
||||
// notes:
|
||||
// - COFF tosses out empty segments, so we have to put in one value
|
||||
// (zero, because CallFunctionPointers has to ignore entries =0 anyway).
|
||||
// - ASCII '$' and 'Z' come before resp. after '0'..'9', so use that to
|
||||
// bound the section names.
|
||||
__declspec(allocate(".WINIT$I$")) PfnLibError initBegin = 0;
|
||||
__declspec(allocate(".WINIT$IZ")) PfnLibError initEnd = 0;
|
||||
__declspec(allocate(".WINIT$S$")) PfnLibError shutdownBegin = 0;
|
||||
__declspec(allocate(".WINIT$SZ")) PfnLibError shutdownEnd = 0;
|
||||
// note: #pragma comment(linker, "/include") is not necessary since
|
||||
// these are referenced below.
|
||||
|
||||
|
||||
/**
|
||||
* call into a range of function pointers.
|
||||
* @param [begin, end): STL-style range
|
||||
*
|
||||
* note: pointers = 0 are ignored. this is because the above placeholders
|
||||
* are initialized to 0 and because the range may be larger than
|
||||
* expected due to COFF section padding (with zeroes).
|
||||
**/
|
||||
static void CallFunctionPointers(PfnLibError* begin, PfnLibError* end)
|
||||
{
|
||||
const DWORD t0 = GetTickCount();
|
||||
|
||||
for(PfnLibError* ppfunc = begin; ppfunc < end; ppfunc++)
|
||||
{
|
||||
if(*ppfunc)
|
||||
{
|
||||
(*ppfunc)();
|
||||
}
|
||||
}
|
||||
|
||||
const DWORD t1 = GetTickCount();
|
||||
debug_printf("WINIT| total elapsed time in callbacks %d ms (+-10)\n", t1-t0);
|
||||
}
|
||||
|
||||
|
||||
void winit_CallInitFunctions()
|
||||
{
|
||||
CallFunctionPointers(&initBegin, &initEnd);
|
||||
}
|
||||
|
||||
void winit_CallShutdownFunctions()
|
||||
{
|
||||
CallFunctionPointers(&shutdownBegin, &shutdownEnd);
|
||||
}
|
@ -1,172 +0,0 @@
|
||||
/* Copyright (C) 2010 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* windows-specific module init and shutdown mechanism
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_WINIT
|
||||
#define INCLUDED_WINIT
|
||||
|
||||
/*
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
This facility allows registering init and shutdown functions with only
|
||||
one line of code and zero runtime overhead. It provides for dependencies
|
||||
between modules, allowing groups of functions to run before others.
|
||||
|
||||
|
||||
Details
|
||||
-------
|
||||
|
||||
Participating modules store function pointer(s) to their init and/or
|
||||
shutdown function in a specific COFF section. The sections are
|
||||
grouped according to the desired notification and the order in which
|
||||
functions are to be called (useful if one module depends on another).
|
||||
They are then gathered by the linker and arranged in alphabetical order.
|
||||
Placeholder variables in the sections indicate where the series of
|
||||
functions begins and ends for a given notification time.
|
||||
At runtime, all of the function pointers between the markers are invoked.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
(at file scope:)
|
||||
WINIT_REGISTER_MAIN_INIT(InitCallback);
|
||||
|
||||
|
||||
Rationale
|
||||
---------
|
||||
|
||||
Several methods of module init are possible: (see Large Scale C++ Design)
|
||||
- on-demand initialization: each exported function would have to check
|
||||
if init already happened. that would be brittle and hard to verify.
|
||||
- singleton: variant of the above, but not applicable to a
|
||||
procedural interface (and quite ugly to boot).
|
||||
- registration: static constructors call a central notification function.
|
||||
module dependencies would be quite difficult to express - this would
|
||||
require a graph or separate lists for each priority (clunky).
|
||||
worse, a fatal flaw is that other C++ constructors may depend on the
|
||||
modules we are initializing and already have run. there is no way
|
||||
to influence ctor call order between separate source files, so
|
||||
this is out of the question.
|
||||
- linker-based registration: same as above, but the linker takes care
|
||||
of assembling various functions into one sorted table. the list of
|
||||
init functions is available before C++ ctors have run. incidentally,
|
||||
zero runtime overhead is incurred. unfortunately, this approach is
|
||||
MSVC-specific. however, the MS CRT uses a similar method for its
|
||||
init, so this is expected to remain supported.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// section declarations
|
||||
|
||||
// section names are of the format ".WINIT${type}{group}".
|
||||
// {type} is I for initialization- or S for shutdown functions.
|
||||
// {group} is [0, 9] - see below.
|
||||
// note: __declspec(allocate) requires declaring segments in advance via
|
||||
// #pragma section.
|
||||
#pragma section(".WINIT$I$", read)
|
||||
#pragma section(".WINIT$I0", read)
|
||||
#pragma section(".WINIT$I1", read)
|
||||
#pragma section(".WINIT$I2", read)
|
||||
#pragma section(".WINIT$I6", read)
|
||||
#pragma section(".WINIT$I7", read)
|
||||
#pragma section(".WINIT$IZ", read)
|
||||
#pragma section(".WINIT$S$", read)
|
||||
#pragma section(".WINIT$S0", read)
|
||||
#pragma section(".WINIT$S1", read)
|
||||
#pragma section(".WINIT$S6", read)
|
||||
#pragma section(".WINIT$S7", read)
|
||||
#pragma section(".WINIT$S8", read)
|
||||
#pragma section(".WINIT$SZ", read)
|
||||
#pragma comment(linker, "/merge:.WINIT=.rdata")
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Function groups
|
||||
|
||||
// to allow correct ordering of module init in the face of dependencies,
|
||||
// we introduce 'groups'. all functions in one are called before those in
|
||||
// the next higher group, but order within the group is undefined.
|
||||
// (this is because the linker sorts sections alphabetically but doesn't
|
||||
// specify the order in which object files are processed.)
|
||||
|
||||
// these macros register a function to be called at the given time.
|
||||
// usage: invoke at file scope, passing a function identifier/symbol.
|
||||
// rationale:
|
||||
// - __declspec(allocate) requires section declarations, but allows users to
|
||||
// write only one line (instead of needing an additional #pragma data_seg)
|
||||
// - fixed groups instead of passing a group number are more clear and
|
||||
// encourage thinking about init order. (__declspec(allocate) requires
|
||||
// a single string literal anyway and doesn't support string merging)
|
||||
// - why EXTERN_C and __pragma? VC8's link-stage optimizer believes
|
||||
// the static function pointers defined by WINIT_REGISTER_* to be unused;
|
||||
// unless action is taken, they would be removed. to prevent this, we
|
||||
// forcibly include the function pointer symbols. this means the variable
|
||||
// must be extern, not static. the linker needs to know the decorated
|
||||
// symbol name, so we disable mangling via EXTERN_C.
|
||||
|
||||
// very early init; must not fail, since error handling code *crashes*
|
||||
// if called before these have completed.
|
||||
#define WINIT_REGISTER_CRITICAL_INIT(func) __pragma(comment(linker, "/include:" STRINGIZE(DECORATED_NAME(p##func)))) static Status func(); EXTERN_C __declspec(allocate(".WINIT$I0")) Status (*p##func)(void) = func
|
||||
|
||||
// meant for modules with dependents but whose init is complicated and may
|
||||
// raise error/warning messages (=> can't go in WINIT_REGISTER_CRITICAL_INIT)
|
||||
#define WINIT_REGISTER_EARLY_INIT(func) __pragma(comment(linker, "/include:" STRINGIZE(DECORATED_NAME(p##func)))) static Status func(); EXTERN_C __declspec(allocate(".WINIT$I1")) Status (*p##func)(void) = func
|
||||
|
||||
// available for dependents of WINIT_REGISTER_EARLY_INIT-modules that
|
||||
// must still come before WINIT_REGISTER_MAIN_INIT.
|
||||
#define WINIT_REGISTER_EARLY_INIT2(func) __pragma(comment(linker, "/include:" STRINGIZE(DECORATED_NAME(p##func)))) static Status func(); EXTERN_C __declspec(allocate(".WINIT$I2")) Status (*p##func)(void) = func
|
||||
|
||||
// most modules will go here unless they are often used or
|
||||
// have many dependents.
|
||||
#define WINIT_REGISTER_MAIN_INIT(func) __pragma(comment(linker, "/include:" STRINGIZE(DECORATED_NAME(p##func)))) static Status func(); EXTERN_C __declspec(allocate(".WINIT$I6")) Status (*p##func)(void) = func
|
||||
|
||||
// available for any modules that may need to come after
|
||||
// WINIT_REGISTER_MAIN_INIT (unlikely)
|
||||
#define WINIT_REGISTER_LATE_INIT(func) __pragma(comment(linker, "/include:" STRINGIZE(DECORATED_NAME(p##func)))) static Status func(); EXTERN_C __declspec(allocate(".WINIT$I7")) Status (*p##func)(void) = func
|
||||
|
||||
#define WINIT_REGISTER_EARLY_SHUTDOWN(func) __pragma(comment(linker, "/include:" STRINGIZE(DECORATED_NAME(p##func)))) static Status func(); EXTERN_C __declspec(allocate(".WINIT$S0")) Status (*p##func)(void) = func
|
||||
#define WINIT_REGISTER_EARLY_SHUTDOWN2(func) __pragma(comment(linker, "/include:" STRINGIZE(DECORATED_NAME(p##func)))) static Status func(); EXTERN_C __declspec(allocate(".WINIT$S1")) Status (*p##func)(void) = func
|
||||
#define WINIT_REGISTER_MAIN_SHUTDOWN(func) __pragma(comment(linker, "/include:" STRINGIZE(DECORATED_NAME(p##func)))) static Status func(); EXTERN_C __declspec(allocate(".WINIT$S6")) Status (*p##func)(void) = func
|
||||
#define WINIT_REGISTER_LATE_SHUTDOWN(func) __pragma(comment(linker, "/include:" STRINGIZE(DECORATED_NAME(p##func)))) static Status func(); EXTERN_C __declspec(allocate(".WINIT$S7")) Status (*p##func)(void) = func
|
||||
#define WINIT_REGISTER_LATE_SHUTDOWN2(func) __pragma(comment(linker, "/include:" STRINGIZE(DECORATED_NAME(p##func)))) static Status func(); EXTERN_C __declspec(allocate(".WINIT$S8")) Status (*p##func)(void) = func
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* call each registered function.
|
||||
*
|
||||
* if this is called before CRT initialization, callbacks must not use any
|
||||
* non-stateless CRT functions such as atexit. see wstartup.h for the
|
||||
* current status on this issue.
|
||||
**/
|
||||
extern void winit_CallInitFunctions();
|
||||
extern void winit_CallShutdownFunctions();
|
||||
|
||||
#endif // #ifndef INCLUDED_WINIT
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
/* Copyright (C) 2023 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
@ -39,13 +39,10 @@
|
||||
#include "lib/sysdep/filesystem.h" // O_DIRECT
|
||||
#include "lib/sysdep/os/win/wutil.h" // wutil_SetPrivilege
|
||||
#include "lib/sysdep/os/win/wiocp.h"
|
||||
#include "lib/sysdep/os/win/winit.h"
|
||||
#include "lib/sysdep/os/win/wposix/crt_posix.h" // _get_osfhandle
|
||||
|
||||
#include <ctime>
|
||||
|
||||
WINIT_REGISTER_MAIN_SHUTDOWN(waio_Shutdown);
|
||||
|
||||
// (dynamic linking preserves compatibility with previous Windows versions)
|
||||
static WUTIL_FUNC(pSetFileCompletionNotificationModes, BOOL, (HANDLE, UCHAR));
|
||||
static WUTIL_FUNC(pSetFileIoOverlappedRange, BOOL, (HANDLE, PUCHAR, ULONG));
|
||||
@ -392,7 +389,7 @@ static Status waio_Init()
|
||||
}
|
||||
|
||||
|
||||
static Status waio_Shutdown()
|
||||
Status waio_Shutdown()
|
||||
{
|
||||
if(waio_initState == 0) // we were never initialized
|
||||
return INFO::OK;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010 Wildfire Games.
|
||||
/* Copyright (C) 2023 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
@ -24,7 +24,6 @@
|
||||
#define INCLUDED_WPOSIX_INTERNAL
|
||||
|
||||
#include "lib/sysdep/os/win/win.h"
|
||||
#include "lib/sysdep/os/win/winit.h"
|
||||
#include "lib/sysdep/os/win/wutil.h"
|
||||
|
||||
// cast intptr_t to HANDLE; centralized for easier changing, e.g. avoiding
|
||||
|
@ -1,123 +0,0 @@
|
||||
/* Copyright (C) 2010 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* windows-specific startup code
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
#include "lib/sysdep/os/win/wstartup.h"
|
||||
|
||||
#include "lib/sysdep/os/win/winit.h"
|
||||
|
||||
/*
|
||||
|
||||
Shutdown
|
||||
--------
|
||||
|
||||
our shutdown function must be called after static C++ dtors, since they
|
||||
may use wpthread and wtime functions. how to accomplish this?
|
||||
|
||||
hooking ExitProcess is one way of ensuring we're the very last bit of
|
||||
code to be called. this has several big problems, though:
|
||||
- if other exit paths (such as CorExitProcess) are added by MS and
|
||||
triggered via external code injected into our process, we miss our cue
|
||||
to shut down. one annoying consequence would be that the Aken driver
|
||||
remains loaded. however, users also can terminate our process at any
|
||||
time, so we need to safely handle lack of shutdown anyway.
|
||||
- IAT hooking breaks if kernel32 is delay-loaded (who knows what
|
||||
people are going to do..)
|
||||
- Detours-style trampolines are nonportable (the Detours library currently
|
||||
only ships with code to handle IA-32) and quite risky, since antivirus
|
||||
programs may flag this activity.
|
||||
|
||||
having all exit paths call our shutdown and then _cexit would work,
|
||||
provided we actually find and control all of them (unhandled exceptions
|
||||
and falling off the end of the last thread are non-obvious examples).
|
||||
that aside, it'd require changes to calling code, and we're trying to
|
||||
keep this mess hidden and transparent to users.
|
||||
|
||||
the remaining alternative is to use atexit. this approach has the
|
||||
advantage of being covered by the CRT runtime checks and leak detector,
|
||||
because those are shut down after the atexit handlers are called.
|
||||
however, it does require that our shutdown callback to be the very last,
|
||||
i.e. registered first. fortunately, the init stage can guarantee this.
|
||||
|
||||
|
||||
Init
|
||||
----
|
||||
|
||||
For the same reasons as above, our init really should happen before static
|
||||
C++ ctors are called.
|
||||
|
||||
using WinMain as the entry point and then calling the application's main()
|
||||
doesn't satisy the above requirement, and is expressly forbidden by ANSI C.
|
||||
(VC apparently makes use of this and changes its calling convention.
|
||||
if we call it, everything appears to work but stack traces in release
|
||||
mode are incorrect, since symbol addresses are off by 4 bytes.)
|
||||
|
||||
another alternative is re#defining the app's main function to app_main,
|
||||
having the OS call our main, and then dispatching to app_main.
|
||||
however, this leads to trouble when another library (e.g. SDL) wants to
|
||||
do the same.
|
||||
moreover, this file is compiled into a static library and used both for
|
||||
the 0ad executable as well as the separate self-test. this means
|
||||
we can't enable the main() hook for one and disable it in the other.
|
||||
|
||||
requiring users to call us at the beginning of main is brittle in general,
|
||||
comes after static ctors, and is difficult to achieve in external code
|
||||
such as the (automatically generated) self-test.
|
||||
|
||||
commandeering the entry point, doing init there and then calling
|
||||
mainCRTStartup would work, but doesn't allow the use of atexit for shutdown
|
||||
(nor any other non-stateless CRT functions to be called during init).
|
||||
|
||||
the way out is to have an init-and-call-atexit function triggered by means
|
||||
of the CRT init mechanism. we arrange init order such that this happens
|
||||
before static C++ ctors, thus meeting all of the above requirements.
|
||||
(note: this is possible because crtexe.c and its .CRT$XI and .CRT$XC
|
||||
sections holding static initializers and ctors are linked into the
|
||||
application, not the CRT DLL.)
|
||||
|
||||
*/
|
||||
|
||||
|
||||
// reference: see http://www.codeguru.com/cpp/misc/misc/threadsprocesses/article.php/c6945__1
|
||||
|
||||
EXTERN_C int wstartup_InitAndRegisterShutdown()
|
||||
{
|
||||
winit_CallInitFunctions();
|
||||
atexit(winit_CallShutdownFunctions);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// insert our initialization function after _cinit and XIU ("User") block
|
||||
#if ARCH_AMD64
|
||||
# define SECTION_ATTRIBUTES read
|
||||
#else
|
||||
# define SECTION_ATTRIBUTES read,write
|
||||
#endif
|
||||
#pragma section(".CRT$XIV", long,SECTION_ATTRIBUTES)
|
||||
#undef SECTION_ATTRIBUTES
|
||||
EXTERN_C __declspec(allocate(".CRT$XIV")) int(*wstartup_pInitAndRegisterShutdown)() = wstartup_InitAndRegisterShutdown;
|
||||
#pragma comment(linker, "/include:" STRINGIZE(DECORATED_NAME(wstartup_pInitAndRegisterShutdown)))
|
@ -1,45 +0,0 @@
|
||||
/* Copyright (C) 2010 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* windows-specific startup code
|
||||
*/
|
||||
|
||||
// linking with this component should automatically arrange for winit's
|
||||
// functions to be called at the appropriate times.
|
||||
//
|
||||
// the current implementation manages to trigger initialization in-between
|
||||
// calls to CRT init and the static C++ ctors. that means wpthread etc.
|
||||
// APIs are safe to use from ctors, and winit initializers are allowed
|
||||
// to use non-stateless CRT functions such as atexit.
|
||||
//
|
||||
// IMPORTANT NOTE: if compiling this into a static lib and not using VC8's
|
||||
// "use library dependency inputs" linking mode, the object file will be
|
||||
// discarded because it does not contain any symbols that resolve another
|
||||
// module's undefined external(s). for a discussion of this topic, see:
|
||||
// http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=144087
|
||||
// workaround: in the main EXE project, reference a symbol from this module,
|
||||
// thus forcing it to be linked in. example:
|
||||
// #pragma comment(linker, "/include:_wstartup_InitAndRegisterShutdown")
|
||||
// (doing that in this module isn't sufficient, because it would only
|
||||
// affect the librarian and its generation of the static lib that holds
|
||||
// this file. instead, the process of linking the main EXE must be fixed.)
|
@ -31,7 +31,6 @@
|
||||
#include "lib/sysdep/sysdep.h"
|
||||
#include "lib/sysdep/os/win/win.h"
|
||||
#include "lib/sysdep/os/win/wdbg.h" // wdbg_assert
|
||||
#include "lib/sysdep/os/win/winit.h"
|
||||
|
||||
#include <shlobj.h> // SHGetFolderPath
|
||||
|
||||
@ -39,10 +38,6 @@
|
||||
#include <SDL_syswm.h>
|
||||
|
||||
|
||||
WINIT_REGISTER_EARLY_INIT(wutil_Init);
|
||||
WINIT_REGISTER_LATE_SHUTDOWN(wutil_Shutdown);
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// safe allocator
|
||||
|
||||
@ -306,7 +301,7 @@ void wutil_EnableHiDPIOnWindows()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static Status wutil_Init()
|
||||
Status wutil_Init()
|
||||
{
|
||||
InitLocks();
|
||||
|
||||
@ -314,7 +309,7 @@ static Status wutil_Init()
|
||||
}
|
||||
|
||||
|
||||
static Status wutil_Shutdown()
|
||||
Status wutil_Shutdown()
|
||||
{
|
||||
ShutdownLocks();
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2022 Wildfire Games.
|
||||
/* Copyright (C) 2023 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -100,6 +100,13 @@ that of Atlas depending on commandline parameters.
|
||||
#endif
|
||||
|
||||
#if OS_WIN
|
||||
// Forward declarations to avoid including Windows dependent headers.
|
||||
Status waio_Shutdown();
|
||||
Status wdir_watch_Init();
|
||||
Status wdir_watch_Shutdown();
|
||||
Status wutil_Init();
|
||||
Status wutil_Shutdown();
|
||||
|
||||
// We don't want to include Windows.h as it might mess up the rest
|
||||
// of the file so we just define DWORD as done in Windef.h.
|
||||
#ifndef DWORD
|
||||
@ -734,6 +741,11 @@ extern "C" int main(int argc, char* argv[])
|
||||
}
|
||||
#endif // OS_UNIX
|
||||
|
||||
#if OS_WIN
|
||||
wutil_Init();
|
||||
wdir_watch_Init();
|
||||
#endif
|
||||
|
||||
EarlyInit(); // must come at beginning of main
|
||||
|
||||
// static_cast is ok, argc is never negative.
|
||||
@ -742,5 +754,13 @@ extern "C" int main(int argc, char* argv[])
|
||||
// Shut down profiler initialised by EarlyInit
|
||||
g_Profiler2.Shutdown();
|
||||
|
||||
#if OS_WIN
|
||||
// All calls to Windows specific functions have to happen before the following
|
||||
// shutdowns.
|
||||
wdir_watch_Shutdown();
|
||||
waio_Shutdown();
|
||||
wutil_Shutdown();
|
||||
#endif
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user