1 | /* |
2 | * PROGRAM: Common Access Method |
3 | * MODULE: init.h |
4 | * DESCRIPTION: InitMutex, InitInstance - templates to help with initialization |
5 | * |
6 | * The contents of this file are subject to the Initial |
7 | * Developer's Public License Version 1.0 (the "License"); |
8 | * you may not use this file except in compliance with the |
9 | * License. You may obtain a copy of the License at |
10 | * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl. |
11 | * |
12 | * Software distributed under the License is distributed AS IS, |
13 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. |
14 | * See the License for the specific language governing rights |
15 | * and limitations under the License. |
16 | * |
17 | * The Original Code was created by Alexander Peshkoff |
18 | * for the Firebird Open Source RDBMS project. |
19 | * |
20 | * Copyright (c) 2004 Alexander Peshkoff <peshkoff@mail.ru> |
21 | * and all contributors signed below. |
22 | * |
23 | * All Rights Reserved. |
24 | * Contributor(s): ______________________________________. |
25 | */ |
26 | |
27 | #ifndef CLASSES_INIT_INSTANCE_H |
28 | #define CLASSES_INIT_INSTANCE_H |
29 | |
30 | #include "fb_types.h" |
31 | #include "../common/classes/alloc.h" |
32 | |
33 | namespace Firebird { |
34 | |
35 | namespace StaticMutex |
36 | { |
37 | // Support for common mutex for various inits |
38 | extern Mutex* mutex; |
39 | void create(); |
40 | void release(); |
41 | } |
42 | |
43 | // InstanceControl - interface for almost all global variables |
44 | |
45 | class InstanceControl |
46 | { |
47 | public: |
48 | enum DtorPriority |
49 | { |
50 | STARTING_PRIORITY, // Not to be used out of class InstanceControl |
51 | PRIORITY_DETECT_UNLOAD, |
52 | PRIORITY_DELETE_FIRST, |
53 | PRIORITY_REGULAR, |
54 | PRIORITY_TLS_KEY |
55 | }; |
56 | |
57 | InstanceControl(); |
58 | |
59 | // |
60 | // GlobalPtr should not be directly derived from class with virtual functions - |
61 | // virtual table for its instances may become invalid in the moment, |
62 | // when cleanup is needed. Therefore indirect link via InstanceList and |
63 | // InstanceLink is established. This means more calls to memory allocator, |
64 | // but who cares for 100 global variables? |
65 | // |
66 | |
67 | class InstanceList |
68 | { |
69 | public: |
70 | explicit InstanceList(DtorPriority p); |
71 | virtual ~InstanceList(); |
72 | static void destructors(); |
73 | |
74 | private: |
75 | InstanceList* next; |
76 | DtorPriority priority; |
77 | virtual void dtor() = 0; |
78 | }; |
79 | |
80 | template <typename T, InstanceControl::DtorPriority P = InstanceControl::PRIORITY_REGULAR> |
81 | class InstanceLink : private InstanceList, public GlobalStorage |
82 | { |
83 | private: |
84 | T* link; |
85 | |
86 | public: |
87 | explicit InstanceLink(T* l) |
88 | : InstanceControl::InstanceList(P), link(l) |
89 | { |
90 | fb_assert(link); |
91 | } |
92 | |
93 | void dtor() |
94 | { |
95 | fb_assert(link); |
96 | if (link) |
97 | { |
98 | link->dtor(); |
99 | link = NULL; |
100 | } |
101 | } |
102 | }; |
103 | |
104 | public: |
105 | static void destructors(); |
106 | static void registerGdsCleanup(FPTR_VOID cleanup); |
107 | static void registerShutdown(FPTR_VOID shutdown); |
108 | }; |
109 | |
110 | |
111 | // GlobalPtr - template to help declaring global varables |
112 | |
113 | template <typename T, InstanceControl::DtorPriority P = InstanceControl::PRIORITY_REGULAR> |
114 | class GlobalPtr : private InstanceControl |
115 | { |
116 | private: |
117 | T* instance; |
118 | |
119 | public: |
120 | void dtor() |
121 | { |
122 | delete instance; |
123 | instance = 0; |
124 | } |
125 | |
126 | GlobalPtr() |
127 | { |
128 | // This means - for objects with ctors/dtors that want to be global, |
129 | // provide ctor with MemoryPool& parameter. Even if it is ignored! |
130 | instance = FB_NEW(*getDefaultMemoryPool()) T(*getDefaultMemoryPool()); |
131 | // Put ourselves into linked list for cleanup. |
132 | // Allocated pointer is saved by InstanceList::constructor. |
133 | new InstanceControl::InstanceLink<GlobalPtr, P>(this); |
134 | } |
135 | |
136 | T* operator->() throw() |
137 | { |
138 | return instance; |
139 | } |
140 | operator T&() throw() |
141 | { |
142 | return *instance; |
143 | } |
144 | T* operator&() throw() |
145 | { |
146 | return instance; |
147 | } |
148 | }; |
149 | |
150 | // InitMutex - executes static void C::init() once and only once |
151 | |
152 | template <typename C> |
153 | class InitMutex |
154 | { |
155 | private: |
156 | volatile bool flag; |
157 | #ifdef DEV_BUILD |
158 | const char* from; |
159 | #endif |
160 | public: |
161 | explicit InitMutex(const char* f) |
162 | : flag(false) |
163 | #ifdef DEV_BUILD |
164 | , from(f) |
165 | #define FB_LOCKED_FROM from |
166 | #else |
167 | #define FB_LOCKED_FROM NULL |
168 | #endif |
169 | { } |
170 | void init() |
171 | { |
172 | if (!flag) |
173 | { |
174 | MutexLockGuard guard(*StaticMutex::mutex, FB_LOCKED_FROM); |
175 | if (!flag) |
176 | { |
177 | C::init(); |
178 | flag = true; |
179 | } |
180 | } |
181 | } |
182 | void cleanup() |
183 | { |
184 | if (flag) |
185 | { |
186 | MutexLockGuard guard(*StaticMutex::mutex, FB_LOCKED_FROM); |
187 | if (flag) |
188 | { |
189 | C::cleanup(); |
190 | flag = false; |
191 | } |
192 | } |
193 | } |
194 | }; |
195 | #undef FB_LOCKED_FROM |
196 | |
197 | // InitInstance - allocate instance of class T on first request. |
198 | |
199 | template <typename T> |
200 | class InitInstance : private InstanceControl |
201 | { |
202 | private: |
203 | T* instance; |
204 | volatile bool flag; |
205 | |
206 | public: |
207 | InitInstance() |
208 | : instance(NULL), flag(false) |
209 | { } |
210 | |
211 | T& operator()() |
212 | { |
213 | if (!flag) |
214 | { |
215 | MutexLockGuard guard(*StaticMutex::mutex, "InitInstance" ); |
216 | if (!flag) |
217 | { |
218 | instance = FB_NEW(*getDefaultMemoryPool()) T(*getDefaultMemoryPool()); |
219 | flag = true; |
220 | // Put ourselves into linked list for cleanup. |
221 | // Allocated pointer is saved by InstanceList::constructor. |
222 | new InstanceControl::InstanceLink<InitInstance>(this); |
223 | } |
224 | } |
225 | return *instance; |
226 | } |
227 | |
228 | void dtor() |
229 | { |
230 | MutexLockGuard guard(*StaticMutex::mutex, "InitInstance - dtor" ); |
231 | flag = false; |
232 | delete instance; |
233 | instance = NULL; |
234 | } |
235 | }; |
236 | |
237 | // Static - create instance of some class in static char[] buffer. Never destroy it. |
238 | |
239 | template <typename T> |
240 | class Static |
241 | { |
242 | private: |
243 | char buf[sizeof(T) + FB_ALIGNMENT]; |
244 | T* t; |
245 | |
246 | public: |
247 | Static() |
248 | { |
249 | t = new((void*) FB_ALIGN(U_IPTR(buf), FB_ALIGNMENT)) T(); |
250 | } |
251 | |
252 | T* operator->() |
253 | { |
254 | return t; |
255 | } |
256 | |
257 | T* operator&() |
258 | { |
259 | return t; |
260 | } |
261 | |
262 | operator T() |
263 | { |
264 | return *t; |
265 | } |
266 | }; |
267 | |
268 | } //namespace Firebird |
269 | |
270 | #endif // CLASSES_INIT_INSTANCE_H |
271 | |