HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
UT_Singleton.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: UT_Singleton.h (UT Library, C++)
7  *
8  * COMMENTS: Classes for on-demand construction of singletons or
9  * pointer member variables.
10  */
11 
12 #ifndef __UT_Singleton__
13 #define __UT_Singleton__
14 
15 #include "UT_NonCopyable.h"
16 #include "UT_LockUtil.h"
17 #include <SYS/SYS_MemoryOrder.h>
18 
19 class UT_Lock;
20 
21 namespace {
22 
23 /// This is a helper function for UT_Singleton and UT_SingletonWithLock.
24 /// Do NOT use it directly unless you know what you're doing.
25 template <typename T, class LOCK>
26 T &
27 UTacquireSingleton(T *volatile &p, LOCK &lock)
28 {
29  // Read into temp to avoid re-reading p with "return *p;",
30  // since p is only written once.
31  T *temp = p;
32  if (!temp)
33  {
34  typename LOCK::Scope autolock(lock);
35 
36  // Read into temp to avoid re-reading p with "return *p;",
37  // since p is only written once.
38  temp = p;
39  if (!temp)
40  {
41  temp = new T();
42 
43  // Ensure that the data that temp refers to is written
44  // out to main memory before setting p.
45  // Without this store fence, the CPU may re-order the
46  // storing of the data in the cache, and another
47  // thread could receive p as non-NULL before
48  // the data pointed-to by p is initialized
49  // in main memory, so the thread could see garbage data.
50  SYSstoreFence();
51 
52  p = temp;
53  }
54  }
55 
56  // NOTE: This load fence is only necessary for preventing speculative
57  // reads of any side effects of new T() producing values from
58  // before the allocation.
59  //
60  // Even if there aren't explicit side effects, there's
61  // the side effect of a new memory block being allocated
62  // on the heap, so just in case, it's probably better to
63  // leave this here. For (a poor) example, if the heap tracks
64  // how much memory it uses, and if the CPU does a following read
65  // of that count speculatively *before* the read of p, the value
66  // read could be the value from *before* p was allocated.
67  SYSloadFence();
68 
69  return *temp;
70 }
71 
72 /// This is a helper function for UT_Singleton and UT_SingletonWithLock.
73 /// This is the same as UTacquireSingleton(T *volatile &p, LOCK &lock),
74 /// except that it passes s, of type S, to the T constructor.
75 /// Do NOT use it directly unless you know what you're doing.
76 template <typename T, class LOCK, typename S>
77 T &
78 UTacquireSingleton(T *volatile &p, LOCK &lock, S s)
79 {
80  // Read into temp to avoid re-reading p with "return *p;",
81  // since p is only written once.
82  T *temp = p;
83  if (!temp)
84  {
85  typename LOCK::Scope autolock(lock);
86 
87  // Read into temp to avoid re-reading p with "return *p;",
88  // since p is only written once.
89  temp = p;
90  if (!temp)
91  {
92  temp = new T(s);
93 
94  // Ensure that the data that temp refers to is written
95  // out to main memory before setting p.
96  // Without this store fence, the CPU may re-order the
97  // storing of the data in the cache, and another
98  // thread could receive p as non-NULL before
99  // the data pointed-to by p is initialized
100  // in main memory, so the thread could see garbage data.
101  SYSstoreFence();
102 
103  p = temp;
104  }
105  }
106 
107  // NOTE: This load fence is only necessary for preventing speculative
108  // reads of any side effects of allocfunc(param) producing values
109  // from before the allocation.
110  //
111  // Even if there aren't explicit side effects, there's
112  // the side effect of a new memory block being allocated
113  // on the heap, so just in case, it's probably better to
114  // leave this here. For (a poor) example, if the heap tracks
115  // how much memory it uses, and if the CPU does a following read
116  // of that count speculatively *before* the read of p, the value
117  // read could be the value from *before* p was allocated.
118  SYSloadFence();
119 
120  return *temp;
121 }
122 
123 } // end of anonymous namespace
124 
125 /// This is the same as UT_SingletonWithLock, except referencing an
126 /// existing lock in get(), instead of holding its own. This can be useful
127 /// for avoiding having many locks as member variables when using
128 /// UT_Singleton for pointer member variables that are allocated
129 /// on-demand, or if another lock would need to be acquired in order
130 /// to run new T().
131 template <typename T, bool DESTRUCTONEXIT=false>
133 {
134 public:
135  UT_Singleton() : myPointer(0) {}
137  {
138  if (DESTRUCTONEXIT)
139  delete myPointer;
140  }
141 
142  template <class LOCK>
143  T &get(LOCK &lock)
144  {
145  return UTacquireSingleton(myPointer, lock);
146  }
147 
148  template <class LOCK, typename S>
149  T &get(LOCK &lock, S s)
150  {
151  return UTacquireSingleton(myPointer, lock, s);
152  }
153 
154  /// NOTE: Even though unsafeSet locks, it is still unsafe, because
155  /// other threads may have called get(), gotten a valid pointer,
156  /// and be using it when unsafeSet destructs it.
157  template <class LOCK>
158  void unsafeSet(LOCK &lock, T *newp)
159  {
160  T *oldp = myPointer;
161  if (oldp != newp)
162  {
163  typename LOCK::Scope autolock(lock);
164 
165  oldp = myPointer;
166  if (oldp != newp)
167  {
168  // Make sure to save out the data pointed to by newp to main
169  // memory before setting myPointer to it.
170  SYSstoreFence();
171 
172  myPointer = newp;
173 
174  if (oldp)
175  delete oldp;
176  }
177  }
178  }
179 
180 private:
181  T *volatile myPointer;
182 };
183 
184 ///
185 /// This is a singleton constructed on-demand with a double-checked lock.
186 /// The lock is only locked if get() is called when myPointer is 0.
187 ///
188 /// This is normally simpler to use than a UT_DoubleLock, and this should
189 /// be used for all on-demand singleton construction, as well as for
190 /// pointer member variables that are allocated on-demand, if applicable.
191 /// If it is preferable in such a case to use an existing lock instead of
192 /// using the lock member in this class, please use UT_Singleton.
193 ///
194 /// To use this class in the simplest case, where OBJECT is to be
195 /// default-constructed:
196 ///
197 /// static UT_SingletonWithLock<OBJECT> theSingleton;
198 ///
199 /// void useSingleton()
200 /// {
201 /// OBJECT &obj = theSingleton.get();
202 /// ...
203 /// }
204 ///
205 /// When special construction or destruction are necessary, subclass
206 /// OBJECT:
207 ///
208 /// class OBJECTWrapper : public OBJECT
209 /// {
210 /// public:
211 /// OBJECTWrapper()
212 /// : OBJECT(12345)
213 /// { doSpecialInit(67890); }
214 /// ~OBJECTWrapper()
215 /// { doBeforeDestruction(7654); }
216 /// };
217 ///
218 /// static UT_SingletonWithLock<OBJECTWrapper> theSingleton;
219 ///
220 /// void useSingleton()
221 /// {
222 /// OBJECT &obj = theSingleton.get();
223 /// ...
224 /// }
225 ///
226 /// NOTE: Do not roll your own on-demand singleton construction!
227 /// This class should be threadsafe, and it's very easy to
228 /// miss a store memory fence without noticing for a very
229 /// long time.
230 ///
231 template <typename T, bool DESTRUCTONEXIT=false, class LOCK=UT_Lock>
232 class UT_SingletonWithLock : public UT_Singleton<T, DESTRUCTONEXIT>
233 {
234 public:
236 
237  T &get()
238  {
239  return Base::get(myLock);
240  }
241 
242  template <typename S>
243  T &get(S s)
244  {
245  return Base::get(myLock, s);
246  }
247 
248  /// NOTE: Even though unsafeSet locks, it is still unsafe, because
249  /// other threads may have called get(), gotten a valid pointer,
250  /// and be using it when unsafeSet destructs it.
251  void unsafeSet(T *newp)
252  {
253  Base::unsafeSet(myLock, newp);
254  }
255 
256  T &operator*() { return get(); }
257  T *operator->() { return &get(); }
258 private:
259  LOCK myLock;
260 };
261 
262 
263 
264 
265 #endif
266 
#define SYSloadFence()
void unsafeSet(LOCK &lock, T *newp)
Definition: UT_Singleton.h:158
#define SYSstoreFence()
void unsafeSet(T *newp)
Definition: UT_Singleton.h:251
T & get(LOCK &lock)
Definition: UT_Singleton.h:143
UT_Singleton< T, DESTRUCTONEXIT > Base
Definition: UT_Singleton.h:235