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