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
33namespace Firebird {
34
35namespace 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
45class InstanceControl
46{
47public:
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
104public:
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
113template <typename T, InstanceControl::DtorPriority P = InstanceControl::PRIORITY_REGULAR>
114class GlobalPtr : private InstanceControl
115{
116private:
117 T* instance;
118
119public:
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
152template <typename C>
153class InitMutex
154{
155private:
156 volatile bool flag;
157#ifdef DEV_BUILD
158 const char* from;
159#endif
160public:
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
199template <typename T>
200class InitInstance : private InstanceControl
201{
202private:
203 T* instance;
204 volatile bool flag;
205
206public:
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
239template <typename T>
240class Static
241{
242private:
243 char buf[sizeof(T) + FB_ALIGNMENT];
244 T* t;
245
246public:
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