1 | /* |
2 | * PROGRAM: Firebird interface. |
3 | * MODULE: ImplementHelper.h |
4 | * DESCRIPTION: Tools to help create interfaces. |
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 Alex Peshkov |
18 | * for the Firebird Open Source RDBMS project. |
19 | * |
20 | * Copyright (c) 2010 Alex Peshkov <peshkoff at mail.ru> |
21 | * and all contributors signed below. |
22 | * |
23 | * All Rights Reserved. |
24 | * Contributor(s): ______________________________________. |
25 | * |
26 | * |
27 | */ |
28 | |
29 | #ifndef FB_COMMON_CLASSES_IMPLEMENT_HELPER |
30 | #define FB_COMMON_CLASSES_IMPLEMENT_HELPER |
31 | |
32 | #include "firebird/Plugin.h" |
33 | #include "firebird/Timer.h" |
34 | #include "firebird/Provider.h" |
35 | #include "../common/classes/alloc.h" |
36 | #include "gen/iberror.h" |
37 | #include "../yvalve/gds_proto.h" |
38 | #include "../common/classes/init.h" |
39 | #include "../common/classes/auto.h" |
40 | #include "../common/classes/RefCounted.h" |
41 | #include "consts_pub.h" |
42 | |
43 | namespace Firebird { |
44 | |
45 | // If you need interface on stack, use template AutoPtr<YourInterface, AutoDisposable> |
46 | // as second parameter to store it. |
47 | typedef SimpleDispose<IDisposable> AutoDisposable; |
48 | |
49 | |
50 | // Implement standard interface and plugin functions |
51 | |
52 | // Helps to implement generic versioned interfaces |
53 | template <class C, int V> |
54 | class VersionedIface : public C |
55 | { |
56 | public: |
57 | VersionedIface() { } |
58 | |
59 | int FB_CARG getVersion() |
60 | { |
61 | return V; |
62 | } |
63 | |
64 | IPluginModule* FB_CARG getModule(); |
65 | |
66 | private: |
67 | VersionedIface(const VersionedIface&); |
68 | VersionedIface& operator=(const VersionedIface&); |
69 | }; |
70 | |
71 | |
72 | // Helps to implement versioned interfaces on stack or static |
73 | template <class C, int V> |
74 | class AutoIface : public VersionedIface<C, V> |
75 | { |
76 | public: |
77 | AutoIface() { } |
78 | |
79 | void* operator new(size_t, void* memory) throw() |
80 | { |
81 | return memory; |
82 | } |
83 | }; |
84 | |
85 | // Helps to implement disposable interfaces |
86 | template <class C, int V> |
87 | class DisposeIface : public VersionedIface<C, V>, public GlobalStorage |
88 | { |
89 | public: |
90 | DisposeIface() { } |
91 | }; |
92 | |
93 | // Helps to implement standard interfaces |
94 | template <class C, int V> |
95 | class RefCntIface : public VersionedIface<C, V>, public GlobalStorage |
96 | { |
97 | public: |
98 | RefCntIface() : refCounter(0) { } |
99 | |
100 | #ifdef DEV_BUILD |
101 | protected: |
102 | ~RefCntIface() |
103 | { |
104 | fb_assert(refCounter.value() == 0); |
105 | } |
106 | |
107 | public: |
108 | #endif |
109 | |
110 | void FB_CARG addRef() |
111 | { |
112 | ++refCounter; |
113 | } |
114 | |
115 | protected: |
116 | AtomicCounter refCounter; |
117 | }; |
118 | |
119 | |
120 | // Helps to implement plugins |
121 | template <class C, int V> |
122 | class StdPlugin : public RefCntIface<C, V> |
123 | { |
124 | private: |
125 | IRefCounted* owner; |
126 | |
127 | public: |
128 | StdPlugin() : owner(NULL) |
129 | { } |
130 | |
131 | IRefCounted* FB_CARG getOwner() |
132 | { |
133 | return owner; |
134 | } |
135 | |
136 | void FB_CARG setOwner(IRefCounted* iface) |
137 | { |
138 | owner = iface; |
139 | } |
140 | }; |
141 | |
142 | |
143 | // Trivial factory |
144 | template <class P> |
145 | class SimpleFactoryBase : public AutoIface<IPluginFactory, FB_PLUGIN_FACTORY_VERSION> |
146 | { |
147 | public: |
148 | IPluginBase* FB_CARG createPlugin(IPluginConfig* factoryParameter) |
149 | { |
150 | P* p = new P(factoryParameter); |
151 | p->addRef(); |
152 | return p; |
153 | } |
154 | }; |
155 | |
156 | template <class P> |
157 | class SimpleFactory : public Static<SimpleFactoryBase<P> > |
158 | { |
159 | }; |
160 | |
161 | |
162 | // Ensure access to cached pointer to master interface |
163 | class CachedMasterInterface |
164 | { |
165 | public: |
166 | static void set(IMaster* master); |
167 | |
168 | protected: |
169 | static IMaster* getMasterInterface(); |
170 | }; |
171 | |
172 | // Base for interface type independent accessors |
173 | template <typename C> |
174 | class AccessAutoInterface : public CachedMasterInterface |
175 | { |
176 | public: |
177 | explicit AccessAutoInterface(C* aPtr) |
178 | : ptr(aPtr) |
179 | { } |
180 | |
181 | operator C*() |
182 | { |
183 | return ptr; |
184 | } |
185 | |
186 | C* operator->() |
187 | { |
188 | return ptr; |
189 | } |
190 | |
191 | private: |
192 | C* ptr; |
193 | }; |
194 | |
195 | // Master interface access |
196 | class MasterInterfacePtr : public AccessAutoInterface<IMaster> |
197 | { |
198 | public: |
199 | MasterInterfacePtr() |
200 | : AccessAutoInterface<IMaster>(getMasterInterface()) |
201 | { } |
202 | }; |
203 | |
204 | |
205 | // Generic plugins interface access |
206 | class PluginManagerInterfacePtr : public AccessAutoInterface<IPluginManager> |
207 | { |
208 | public: |
209 | PluginManagerInterfacePtr() |
210 | : AccessAutoInterface<IPluginManager>(getMasterInterface()->getPluginManager()) |
211 | { } |
212 | /* explicit PluginManagerInterfacePtr(IMaster* master) |
213 | : AccessAutoInterface<IPluginManager>(master->getPluginManager()) |
214 | { } */ |
215 | }; |
216 | |
217 | |
218 | // Control timer interface access |
219 | class TimerInterfacePtr : public AccessAutoInterface<ITimerControl> |
220 | { |
221 | public: |
222 | TimerInterfacePtr() |
223 | : AccessAutoInterface<ITimerControl>(getMasterInterface()->getTimerControl()) |
224 | { } |
225 | }; |
226 | |
227 | |
228 | // Distributed transactions coordinator access |
229 | class DtcInterfacePtr : public AccessAutoInterface<IDtc> |
230 | { |
231 | public: |
232 | DtcInterfacePtr() |
233 | : AccessAutoInterface<IDtc>(getMasterInterface()->getDtc()) |
234 | { } |
235 | }; |
236 | |
237 | |
238 | // Dispatcher access |
239 | class DispatcherPtr : public AccessAutoInterface<IProvider> |
240 | { |
241 | public: |
242 | DispatcherPtr() |
243 | : AccessAutoInterface<IProvider>(getMasterInterface()->getDispatcher()) |
244 | { } |
245 | |
246 | ~DispatcherPtr() |
247 | { |
248 | (*this)->release(); |
249 | } |
250 | }; |
251 | |
252 | |
253 | // Misc utl access |
254 | class UtlInterfacePtr : public AccessAutoInterface<IUtl> |
255 | { |
256 | public: |
257 | UtlInterfacePtr() |
258 | : AccessAutoInterface<IUtl>(getMasterInterface()->getUtlInterface()) |
259 | { } |
260 | }; |
261 | |
262 | |
263 | // When process exits, dynamically loaded modules (for us plugin modules) |
264 | // are unloaded first. As the result all global variables in plugin are already destroyed |
265 | // when yvalve is starting fb_shutdown(). This causes almost unavoidable segfault. |
266 | // To avoid it this class is added - it detects spontaneous (not by PluginManager) |
267 | // module unload and notifies PluginManager about this said fact. |
268 | class UnloadDetectorHelper FB_FINAL : public VersionedIface<IPluginModule, FB_PLUGIN_MODULE_VERSION> |
269 | { |
270 | public: |
271 | typedef void VoidNoParam(); |
272 | |
273 | explicit UnloadDetectorHelper(MemoryPool&) |
274 | : cleanup(NULL), flagOsUnload(false) |
275 | { } |
276 | |
277 | void registerMe() |
278 | { |
279 | PluginManagerInterfacePtr()->registerModule(this); |
280 | flagOsUnload = true; |
281 | } |
282 | |
283 | ~UnloadDetectorHelper() |
284 | { |
285 | if (flagOsUnload) |
286 | { |
287 | PluginManagerInterfacePtr()->unregisterModule(this); |
288 | doClean(); |
289 | } |
290 | } |
291 | |
292 | bool unloadStarted() |
293 | { |
294 | return !flagOsUnload; |
295 | } |
296 | |
297 | void setCleanup(VoidNoParam* function) |
298 | { |
299 | cleanup = function; |
300 | } |
301 | |
302 | private: |
303 | VoidNoParam* cleanup; |
304 | bool flagOsUnload; |
305 | |
306 | void FB_CARG doClean() |
307 | { |
308 | flagOsUnload = false; |
309 | |
310 | if (cleanup) |
311 | { |
312 | cleanup(); |
313 | cleanup = NULL; |
314 | } |
315 | } |
316 | }; |
317 | |
318 | typedef GlobalPtr<UnloadDetectorHelper, InstanceControl::PRIORITY_DETECT_UNLOAD> UnloadDetector; |
319 | extern UnloadDetector myModule; |
320 | |
321 | template <class C, int V> IPluginModule* VersionedIface<C, V>::getModule() |
322 | { |
323 | return &myModule; |
324 | } |
325 | |
326 | |
327 | // Default replacement for missing virtual functions |
328 | class DefaultMissingEntrypoint |
329 | { |
330 | public: |
331 | virtual void FB_CARG noEntrypoint() |
332 | { |
333 | Arg::Gds(isc_wish_list).raise(); |
334 | } |
335 | }; |
336 | |
337 | |
338 | // Helps to create update information |
339 | template <typename M = DefaultMissingEntrypoint> |
340 | class MakeUpgradeInfo |
341 | { |
342 | public: |
343 | MakeUpgradeInfo() |
344 | { |
345 | ui.missingFunctionClass = &missing; |
346 | ui.clientModule = &myModule; |
347 | } |
348 | |
349 | operator UpgradeInfo*() |
350 | { |
351 | return &ui; |
352 | } |
353 | |
354 | private: |
355 | M missing; |
356 | struct UpgradeInfo ui; |
357 | }; |
358 | |
359 | |
360 | // debugger for reference counters |
361 | |
362 | #ifdef DEV_BUILD |
363 | #define FB_CAT2(a, b) a##b |
364 | #define FB_CAT1(a, b) FB_CAT2(a, b) |
365 | #define FB_RefDeb(c, p, l) Firebird::ReferenceCounterDebugger FB_CAT1(refCntDbg_, l)(c, p) |
366 | #define RefDeb(c, p) FB_RefDeb(c, p, __LINE__) |
367 | |
368 | enum DebugEvent |
369 | { DEB_RLS_JATT, DEB_RLS_YATT, MaxDebugEvent }; |
370 | |
371 | class ReferenceCounterDebugger |
372 | { |
373 | public: |
374 | ReferenceCounterDebugger(DebugEvent code, const char* p); |
375 | ~ReferenceCounterDebugger(); |
376 | static ReferenceCounterDebugger* get(DebugEvent code); |
377 | |
378 | const char* rcd_point; |
379 | ReferenceCounterDebugger* rcd_prev; |
380 | DebugEvent rcd_code; |
381 | }; |
382 | |
383 | extern IDebug* getImpDebug(); |
384 | |
385 | #else |
386 | #define RefDeb(c, p) |
387 | #endif |
388 | |
389 | } // namespace Firebird |
390 | |
391 | #endif // FB_COMMON_CLASSES_IMPLEMENT_HELPER |
392 | |