QDP++
qdp_singleton.h
Go to the documentation of this file.
1// -*- C++ -*-
5
6#ifndef __qdp_singleton_h__
7#define __qdp_singleton_h__
8
9#include <algorithm>
10#include <stdexcept>
11#include <cassert>
12#include <cstdlib>
13#include <new>
14
15namespace QDP
16{
17
19// class template SingleThreaded
20// Implementation of the ThreadingModel policy used by various classes
21// Implements a single-threaded model; no synchronization
23
24 template <class Host>
26 {
27 public:
28 struct Lock
29 {
30 Lock() {}
31 Lock(const Host&) {}
32 };
33
34 typedef Host VolatileType;
35
36 typedef int IntType;
37
38 static IntType AtomicAdd(volatile IntType& lval, IntType val)
39 { return lval += val; }
40
41 static IntType AtomicSubtract(volatile IntType& lval, IntType val)
42 { return lval -= val; }
43
44 static IntType AtomicMultiply(volatile IntType& lval, IntType val)
45 { return lval *= val; }
46
47 static IntType AtomicDivide(volatile IntType& lval, IntType val)
48 { return lval /= val; }
49
50 static IntType AtomicIncrement(volatile IntType& lval)
51 { return ++lval; }
52
53 static IntType AtomicDivide(volatile IntType& lval)
54 { return --lval; }
55
56 static void AtomicAssign(volatile IntType & lval, IntType val)
57 { lval = val; }
58
59 static void AtomicAssign(IntType & lval, volatile IntType & val)
60 { lval = val; }
61 };
62
63
64
65 namespace Private
66 {
68// class LifetimeTracker
69// Helper class for SetLongevity
71
73 {
74 public:
75 LifetimeTracker(unsigned int x) : longevity_(x)
76 {}
77
78 virtual ~LifetimeTracker() = 0;
79
80 static bool Compare(const LifetimeTracker* lhs,
81 const LifetimeTracker* rhs)
82 {
83 return rhs->longevity_ > lhs->longevity_;
84 }
85
86 private:
87 unsigned int longevity_;
88 };
89
90 // Definition required
92
93 // Helper data
96 extern unsigned int elements;
97
98 // Helper destroyer function
99 template <typename T>
100 struct Deleter
101 {
102 static void Delete(T* pObj)
103 { delete pObj; }
104 };
105
106 // Concrete lifetime tracker for objects of type T
107 template <typename T, typename Destroyer>
109 {
110 public:
111 ConcreteLifetimeTracker(T* p,unsigned int longevity, Destroyer d)
112 : LifetimeTracker(longevity)
113 , pTracked_(p)
114 , destroyer_(d)
115 {}
116
118 { destroyer_(pTracked_); }
119
120 private:
121 T* pTracked_;
122 Destroyer destroyer_;
123 };
124
125 void AtExitFn(); // declaration needed below
126
127 } // namespace Private
128
130// function template SetLongevity
131// Assigns an object a longevity; ensures ordered destructions of objects
132// registered thusly during the exit sequence of the application
134
135 template <typename T, typename Destroyer>
136 void SetLongevity(T* pDynObject, unsigned int longevity,
137 Destroyer d = Private::Deleter<T>::Delete)
138 {
139 using namespace Private;
140
141 TrackerArray pNewArray = static_cast<TrackerArray>(
142 std::realloc(pTrackerArray, elements + 1));
143 if (!pNewArray) throw std::bad_alloc();
144
145 LifetimeTracker* p = new ConcreteLifetimeTracker<T, Destroyer>(
146 pDynObject, longevity, d);
147
148 // Delayed assignment for exception safety
149 pTrackerArray = pNewArray;
150
151 // Insert a pointer to the object into the queue
152 TrackerArray pos = std::upper_bound(
153 pTrackerArray,
154 pTrackerArray + elements,
155 p,
156 LifetimeTracker::Compare);
157 std::copy_backward(
158 pos,
159 pTrackerArray + elements,
160 pTrackerArray + elements + 1);
161 *pos = p;
162 ++elements;
163
164 // Register a call to AtExitFn
165 std::atexit(Private::AtExitFn);
166 }
167
169// class template CreateUsingNew
170// Implementation of the CreationPolicy used by SingletonHolder
171// Creates objects using a straight call to the new operator
173
174 template <class T> struct CreateUsingNew
175 {
176 static T* Create()
177 { return new T; }
178
179 static void Destroy(T* p)
180 { delete p; }
181 };
182
184// class template CreateUsingNew
185// Implementation of the CreationPolicy used by SingletonHolder
186// Creates objects using a call to std::malloc, followed by a call to the
187// placement new operator
189
190 template <class T> struct CreateUsingMalloc
191 {
192 static T* Create()
193 {
194 void* p = std::malloc(sizeof(T));
195 if (!p) return 0;
196 return new(p) T;
197 }
198
199 static void Destroy(T* p)
200 {
201 p->~T();
202 std::free(p);
203 }
204 };
205
207// class template CreateStatic
208// Implementation of the CreationPolicy used by SingletonHolder
209// Creates an object in static memory
210// Implementation is slightly nonportable because it uses the MaxAlign trick
211// (an union of all types to ensure proper memory alignment). This trick is
212// nonportable in theory but highly portable in practice.
214
215 template <class T> struct CreateStatic
216 {
218 {
219 char t_[sizeof(T)];
220 short int shortInt_;
221 int int_;
222 long int longInt_;
223 float float_;
224 double double_;
225 long double longDouble_;
226 struct Test;
227 int Test::* pMember_;
228 int (Test::*pMemberFn_)(int);
229 };
230
231 static T* Create()
232 {
233 static MaxAlign staticMemory_;
234 return new(&staticMemory_) T;
235 }
236
237 static void Destroy(T* p)
238 {
239 p->~T();
240 }
241 };
242
244// class template DefaultLifetime
245// Implementation of the LifetimePolicy used by SingletonHolder
246// Schedules an object's destruction as per C++ rules
247// Forwards to std::atexit
249
250 template <class T>
252 {
253 static void ScheduleDestruction(T*, void (*pFun)())
254 { std::atexit(pFun); }
255
256 static void OnDeadReference()
257 { throw std::logic_error("Dead Reference Detected"); }
258 };
259
261// class template PhoenixSingleton
262// Implementation of the LifetimePolicy used by SingletonHolder
263// Schedules an object's destruction as per C++ rules, and it allows object
264// recreation by not throwing an exception from OnDeadReference
266
267 template <class T>
269 {
270 public:
271 static void ScheduleDestruction(T*, void (*pFun)())
272 {
273#ifndef ATEXIT_FIXED
274 if (!destroyedOnce_)
275#endif
276 std::atexit(pFun);
277 }
278
279 static void OnDeadReference()
280 {
281#ifndef ATEXIT_FIXED
282 destroyedOnce_ = true;
283#endif
284 }
285
286 private:
287#ifndef ATEXIT_FIXED
288 static bool destroyedOnce_;
289#endif
290 };
291
292#ifndef ATEXIT_FIXED
293 template <class T> bool PhoenixSingleton<T>::destroyedOnce_ = false;
294#endif
295
297// class template Adapter
298// Helper for SingletonWithLongevity below
300
301 namespace Private
302 {
303 template <class T>
304 struct Adapter
305 {
306 void operator()(T*) { return pFun_(); }
307 void (*pFun_)();
308 };
309 }
310
312// class template SingletonWithLongevity
313// Implementation of the LifetimePolicy used by SingletonHolder
314// Schedules an object's destruction in order of their longevities
315// Assumes a visible function GetLongevity(T*) that returns the longevity of the
316// object
318
319 template <class T>
321 {
322 public:
323 static void ScheduleDestruction(T* pObj, void (*pFun)())
324 {
325 Private::Adapter<T> adapter = { pFun };
326 SetLongevity(pObj, GetLongevity(pObj), adapter);
327 }
328
329 static void OnDeadReference()
330 { throw std::logic_error("Dead Reference Detected"); }
331 };
332
334// class template NoDestroy
335// Implementation of the LifetimePolicy used by SingletonHolder
336// Never destroys the object
338
339 template <class T>
341 {
342 static void ScheduleDestruction(T*, void (*pFun)())
343 {} /* Put this back removed memory leak here */
344 /* { std::atexit(pFun); } */
345
346 static void OnDeadReference()
347 {}
348 };
349
351// class template SingletonHolder
352// Provides Singleton amenities for a type T
353// To protect that type from spurious instantiations, you have to protect it
354// yourself.
356
357 template <typename T,
358 template <class> class CreationPolicy = CreateUsingNew,
359 template <class> class LifetimePolicy = DefaultLifetime,
360 template <class> class ThreadingModel = SingleThreaded>
361 class SingletonHolder
362 {
363 public:
364 static T& Instance();
365
366 private:
367 // Helpers
368 static void MakeInstance();
369 static void DestroySingleton();
370
371 // Protection
372 SingletonHolder() {}
374 SingletonHolder& operator= (const SingletonHolder&) {}
375
376 // Data
377 typedef typename ThreadingModel<T*>::VolatileType PtrInstanceType;
378 static PtrInstanceType pInstance_;
379 static bool destroyed_;
380 };
381
383// SingletonHolder's data
385
386 template <class T,
387 template <class> class C,
388 template <class> class L,
389 template <class> class M>
390 typename SingletonHolder<T, C, L, M>::PtrInstanceType
391 SingletonHolder<T, C, L, M>::pInstance_=0;
392
393 template
394 <
395 class T,
396 template <class> class C,
397 template <class> class L,
398 template <class> class M
399 >
400 bool SingletonHolder<T, C, L, M>::destroyed_=false;
401
403// SingletonHolder::Instance
405
406 template <class T,
407 template <class> class CreationPolicy,
408 template <class> class LifetimePolicy,
409 template <class> class ThreadingModel>
410 inline T& SingletonHolder<T, CreationPolicy,
411 LifetimePolicy, ThreadingModel>::Instance()
412 {
413 if (!pInstance_)
414 {
415 MakeInstance();
416 }
417 return *pInstance_;
418 }
419
421// SingletonHolder::MakeInstance (helper for Instance)
423
424 template <class T,
425 template <class> class CreationPolicy,
426 template <class> class LifetimePolicy,
427 template <class> class ThreadingModel>
428 void SingletonHolder<T, CreationPolicy,
429 LifetimePolicy, ThreadingModel>::MakeInstance()
430 {
431 typename ThreadingModel<T>::Lock guard;
432 (void)guard;
433
434 if (!pInstance_)
435 {
436 if (destroyed_)
437 {
438 LifetimePolicy<T>::OnDeadReference();
439 destroyed_ = false;
440 }
441 pInstance_ = CreationPolicy<T>::Create();
442 LifetimePolicy<T>::ScheduleDestruction(pInstance_,
443 &DestroySingleton);
444 }
445 }
446
447 template <class T,
448 template <class> class CreationPolicy,
449 template <class> class L,
450 template <class> class M>
451 void SingletonHolder<T, CreationPolicy, L, M>::DestroySingleton()
452 {
453 assert(!destroyed_);
454 CreationPolicy<T>::Destroy(pInstance_);
455 pInstance_ = 0;
456 destroyed_ = true;
457 }
458} // namespace Chroma
459
460
461#endif
static void ScheduleDestruction(T *, void(*pFun)())
static void OnDeadReference()
ConcreteLifetimeTracker(T *p, unsigned int longevity, Destroyer d)
static bool Compare(const LifetimeTracker *lhs, const LifetimeTracker *rhs)
static IntType AtomicSubtract(volatile IntType &lval, IntType val)
static IntType AtomicIncrement(volatile IntType &lval)
static IntType AtomicDivide(volatile IntType &lval, IntType val)
static void AtomicAssign(volatile IntType &lval, IntType val)
static IntType AtomicDivide(volatile IntType &lval)
static IntType AtomicAdd(volatile IntType &lval, IntType val)
static IntType AtomicMultiply(volatile IntType &lval, IntType val)
static void AtomicAssign(IntType &lval, volatile IntType &val)
static void ScheduleDestruction(T *pObj, void(*pFun)())
OLattice< PScalar< PColorMatrix< RComplexFloat, 3 > > > C
TrackerArray pTrackerArray
LifetimeTracker ** TrackerArray
unsigned int elements
void AtExitFn()
Yet another random number generator.
bool PhoenixSingleton< T >::destroyedOnce_
void SetLongevity(T *pDynObject, unsigned int longevity, Destroyer d=Private::Deleter< T >::Delete)
bool SingletonHolder< T, C, L, M >::destroyed_
SingletonHolder< T, C, L, M >::PtrInstanceType SingletonHolder< T, C, L, M >::pInstance_
static T * Create()
static void Destroy(T *p)
static void Destroy(T *p)
static void Destroy(T *p)
static void OnDeadReference()
static void ScheduleDestruction(T *, void(*pFun)())
static void OnDeadReference()
static void ScheduleDestruction(T *, void(*pFun)())
static void Delete(T *pObj)
int(Test::* pMemberFn_)(int)