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
43namespace Firebird {
44
45// If you need interface on stack, use template AutoPtr<YourInterface, AutoDisposable>
46// as second parameter to store it.
47typedef SimpleDispose<IDisposable> AutoDisposable;
48
49
50// Implement standard interface and plugin functions
51
52// Helps to implement generic versioned interfaces
53template <class C, int V>
54class VersionedIface : public C
55{
56public:
57 VersionedIface() { }
58
59 int FB_CARG getVersion()
60 {
61 return V;
62 }
63
64 IPluginModule* FB_CARG getModule();
65
66private:
67 VersionedIface(const VersionedIface&);
68 VersionedIface& operator=(const VersionedIface&);
69};
70
71
72// Helps to implement versioned interfaces on stack or static
73template <class C, int V>
74class AutoIface : public VersionedIface<C, V>
75{
76public:
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
86template <class C, int V>
87class DisposeIface : public VersionedIface<C, V>, public GlobalStorage
88{
89public:
90 DisposeIface() { }
91};
92
93// Helps to implement standard interfaces
94template <class C, int V>
95class RefCntIface : public VersionedIface<C, V>, public GlobalStorage
96{
97public:
98 RefCntIface() : refCounter(0) { }
99
100#ifdef DEV_BUILD
101protected:
102 ~RefCntIface()
103 {
104 fb_assert(refCounter.value() == 0);
105 }
106
107public:
108#endif
109
110 void FB_CARG addRef()
111 {
112 ++refCounter;
113 }
114
115protected:
116 AtomicCounter refCounter;
117};
118
119
120// Helps to implement plugins
121template <class C, int V>
122class StdPlugin : public RefCntIface<C, V>
123{
124private:
125 IRefCounted* owner;
126
127public:
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
144template <class P>
145class SimpleFactoryBase : public AutoIface<IPluginFactory, FB_PLUGIN_FACTORY_VERSION>
146{
147public:
148 IPluginBase* FB_CARG createPlugin(IPluginConfig* factoryParameter)
149 {
150 P* p = new P(factoryParameter);
151 p->addRef();
152 return p;
153 }
154};
155
156template <class P>
157class SimpleFactory : public Static<SimpleFactoryBase<P> >
158{
159};
160
161
162// Ensure access to cached pointer to master interface
163class CachedMasterInterface
164{
165public:
166 static void set(IMaster* master);
167
168protected:
169 static IMaster* getMasterInterface();
170};
171
172// Base for interface type independent accessors
173template <typename C>
174class AccessAutoInterface : public CachedMasterInterface
175{
176public:
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
191private:
192 C* ptr;
193};
194
195// Master interface access
196class MasterInterfacePtr : public AccessAutoInterface<IMaster>
197{
198public:
199 MasterInterfacePtr()
200 : AccessAutoInterface<IMaster>(getMasterInterface())
201 { }
202};
203
204
205// Generic plugins interface access
206class PluginManagerInterfacePtr : public AccessAutoInterface<IPluginManager>
207{
208public:
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
219class TimerInterfacePtr : public AccessAutoInterface<ITimerControl>
220{
221public:
222 TimerInterfacePtr()
223 : AccessAutoInterface<ITimerControl>(getMasterInterface()->getTimerControl())
224 { }
225};
226
227
228// Distributed transactions coordinator access
229class DtcInterfacePtr : public AccessAutoInterface<IDtc>
230{
231public:
232 DtcInterfacePtr()
233 : AccessAutoInterface<IDtc>(getMasterInterface()->getDtc())
234 { }
235};
236
237
238// Dispatcher access
239class DispatcherPtr : public AccessAutoInterface<IProvider>
240{
241public:
242 DispatcherPtr()
243 : AccessAutoInterface<IProvider>(getMasterInterface()->getDispatcher())
244 { }
245
246 ~DispatcherPtr()
247 {
248 (*this)->release();
249 }
250};
251
252
253// Misc utl access
254class UtlInterfacePtr : public AccessAutoInterface<IUtl>
255{
256public:
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.
268class UnloadDetectorHelper FB_FINAL : public VersionedIface<IPluginModule, FB_PLUGIN_MODULE_VERSION>
269{
270public:
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
302private:
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
318typedef GlobalPtr<UnloadDetectorHelper, InstanceControl::PRIORITY_DETECT_UNLOAD> UnloadDetector;
319extern UnloadDetector myModule;
320
321template <class C, int V> IPluginModule* VersionedIface<C, V>::getModule()
322{
323 return &myModule;
324}
325
326
327// Default replacement for missing virtual functions
328class DefaultMissingEntrypoint
329{
330public:
331 virtual void FB_CARG noEntrypoint()
332 {
333 Arg::Gds(isc_wish_list).raise();
334 }
335};
336
337
338// Helps to create update information
339template <typename M = DefaultMissingEntrypoint>
340class MakeUpgradeInfo
341{
342public:
343 MakeUpgradeInfo()
344 {
345 ui.missingFunctionClass = &missing;
346 ui.clientModule = &myModule;
347 }
348
349 operator UpgradeInfo*()
350 {
351 return &ui;
352 }
353
354private:
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
368enum DebugEvent
369{ DEB_RLS_JATT, DEB_RLS_YATT, MaxDebugEvent };
370
371class ReferenceCounterDebugger
372{
373public:
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
383extern 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