Pyrogenesis  trunk
winit.h
Go to the documentation of this file.
1 /* Copyright (c) 2010 Wildfire Games
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining
4  * a copy of this software and associated documentation files (the
5  * "Software"), to deal in the Software without restriction, including
6  * without limitation the rights to use, copy, modify, merge, publish,
7  * distribute, sublicense, and/or sell copies of the Software, and to
8  * permit persons to whom the Software is furnished to do so, subject to
9  * the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 /*
24  * windows-specific module init and shutdown mechanism
25  */
26 
27 #ifndef INCLUDED_WINIT
28 #define INCLUDED_WINIT
29 
30 /*
31 
32 Overview
33 --------
34 
35 This facility allows registering init and shutdown functions with only
36 one line of code and zero runtime overhead. It provides for dependencies
37 between modules, allowing groups of functions to run before others.
38 
39 
40 Details
41 -------
42 
43 Participating modules store function pointer(s) to their init and/or
44 shutdown function in a specific COFF section. The sections are
45 grouped according to the desired notification and the order in which
46 functions are to be called (useful if one module depends on another).
47 They are then gathered by the linker and arranged in alphabetical order.
48 Placeholder variables in the sections indicate where the series of
49 functions begins and ends for a given notification time.
50 At runtime, all of the function pointers between the markers are invoked.
51 
52 
53 Example
54 -------
55 
56 (at file scope:)
57 WINIT_REGISTER_MAIN_INIT(InitCallback);
58 
59 
60 Rationale
61 ---------
62 
63 Several methods of module init are possible: (see Large Scale C++ Design)
64 - on-demand initialization: each exported function would have to check
65  if init already happened. that would be brittle and hard to verify.
66 - singleton: variant of the above, but not applicable to a
67  procedural interface (and quite ugly to boot).
68 - registration: static constructors call a central notification function.
69  module dependencies would be quite difficult to express - this would
70  require a graph or separate lists for each priority (clunky).
71  worse, a fatal flaw is that other C++ constructors may depend on the
72  modules we are initializing and already have run. there is no way
73  to influence ctor call order between separate source files, so
74  this is out of the question.
75 - linker-based registration: same as above, but the linker takes care
76  of assembling various functions into one sorted table. the list of
77  init functions is available before C++ ctors have run. incidentally,
78  zero runtime overhead is incurred. unfortunately, this approach is
79  MSVC-specific. however, the MS CRT uses a similar method for its
80  init, so this is expected to remain supported.
81 
82 */
83 
84 
85 //-----------------------------------------------------------------------------
86 // section declarations
87 
88 // section names are of the format ".WINIT${type}{group}".
89 // {type} is I for initialization- or S for shutdown functions.
90 // {group} is [0, 9] - see below.
91 // note: __declspec(allocate) requires declaring segments in advance via
92 // #pragma section.
93 #pragma section(".WINIT$I$", read)
94 #pragma section(".WINIT$I0", read)
95 #pragma section(".WINIT$I1", read)
96 #pragma section(".WINIT$I2", read)
97 #pragma section(".WINIT$I6", read)
98 #pragma section(".WINIT$I7", read)
99 #pragma section(".WINIT$IZ", read)
100 #pragma section(".WINIT$S$", read)
101 #pragma section(".WINIT$S0", read)
102 #pragma section(".WINIT$S1", read)
103 #pragma section(".WINIT$S6", read)
104 #pragma section(".WINIT$S7", read)
105 #pragma section(".WINIT$S8", read)
106 #pragma section(".WINIT$SZ", read)
107 #pragma comment(linker, "/merge:.WINIT=.rdata")
108 
109 
110 //-----------------------------------------------------------------------------
111 // Function groups
112 
113 // to allow correct ordering of module init in the face of dependencies,
114 // we introduce 'groups'. all functions in one are called before those in
115 // the next higher group, but order within the group is undefined.
116 // (this is because the linker sorts sections alphabetically but doesn't
117 // specify the order in which object files are processed.)
118 
119 // these macros register a function to be called at the given time.
120 // usage: invoke at file scope, passing a function identifier/symbol.
121 // rationale:
122 // - __declspec(allocate) requires section declarations, but allows users to
123 // write only one line (instead of needing an additional #pragma data_seg)
124 // - fixed groups instead of passing a group number are more clear and
125 // encourage thinking about init order. (__declspec(allocate) requires
126 // a single string literal anyway and doesn't support string merging)
127 // - why EXTERN_C and __pragma? VC8's link-stage optimizer believes
128 // the static function pointers defined by WINIT_REGISTER_* to be unused;
129 // unless action is taken, they would be removed. to prevent this, we
130 // forcibly include the function pointer symbols. this means the variable
131 // must be extern, not static. the linker needs to know the decorated
132 // symbol name, so we disable mangling via EXTERN_C.
133 
134 // very early init; must not fail, since error handling code *crashes*
135 // if called before these have completed.
136 #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
137 
138 // meant for modules with dependents but whose init is complicated and may
139 // raise error/warning messages (=> can't go in WINIT_REGISTER_CRITICAL_INIT)
140 #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
141 
142 // available for dependents of WINIT_REGISTER_EARLY_INIT-modules that
143 // must still come before WINIT_REGISTER_MAIN_INIT.
144 #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
145 
146 // most modules will go here unless they are often used or
147 // have many dependents.
148 #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
149 
150 // available for any modules that may need to come after
151 // WINIT_REGISTER_MAIN_INIT (unlikely)
152 #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
153 
154 #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
155 #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
156 #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
157 #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
158 #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
159 
160 //-----------------------------------------------------------------------------
161 
162 /**
163  * call each registered function.
164  *
165  * if this is called before CRT initialization, callbacks must not use any
166  * non-stateless CRT functions such as atexit. see wstartup.h for the
167  * current status on this issue.
168  **/
169 extern void winit_CallInitFunctions();
170 extern void winit_CallShutdownFunctions();
171 
172 #endif // #ifndef INCLUDED_WINIT
void winit_CallShutdownFunctions()
Definition: winit.cpp:92
void winit_CallInitFunctions()
call each registered function.
Definition: winit.cpp:87