HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_DoubleLock.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_DoubleLock.h ( UT Library, C++)
7  *
8  * COMMENTS:
9  */
10 
11 #ifndef __UT_DoubleLock__
12 #define __UT_DoubleLock__
13 
14 #include "UT_API.h"
15 #include "UT_Lock.h"
16 #include "UT_NonCopyable.h"
17 #include "UT_UniquePtr.h"
18 #include <SYS/SYS_MemoryOrder.h>
19 
20 ///
21 /// A double-checked lock. Only locks the thread lock when the value is 0.
22 ///
23 /// To use this lock:
24 ///
25 /// static UT_Lock theLock;
26 /// static OBJECT *theObj = 0;
27 ///
28 /// OBJECT *
29 /// getSingleton()
30 /// {
31 /// UT_DoubleLock<OBJECT *> lock(theLock, theObj);
32 ///
33 /// if (!lock.getValue())
34 /// {
35 /// // NOTE: This doesn't set theObj. theObj is set when
36 /// // destructing lock.
37 /// lock.setValue(new OBJECT());
38 /// }
39 /// return lock.getValue();
40 /// }
41 ///
42 /// NOTE: DO NOT roll your own double checked lock! If you
43 /// don't know when to use which memory fences and why,
44 /// odds are high that your custom implementation will be
45 /// thread-unsafe.
46 ///
47 /// For simple singleton initialization, consider using UT_Singleton.
48 ///
49 template <typename ValueT, typename LockT = UT_Lock>
51 {
52  template <typename Y> class ValueTrait;
53  template <typename Y, typename DT> class ValueTrait<UT_UniquePtr<Y, DT>>;
54  template <typename Y, typename DT> class ValueTrait<UT_UniquePtr<Y[], DT>>;
55 
56  using TraitT = ValueTrait<ValueT>;
57 
58 public:
59  using GetT = typename TraitT::GetT;
60  using SetT = typename TraitT::SetT;
61  static_assert(sizeof(ValueT) == sizeof(GetT), "T is not trivial");
62 
63  UT_DoubleLock(LockT &lock, volatile ValueT &val)
64  : myLock(lock)
65  , myValue(val)
66  , myPendingValue{} // default value initialize
67  , myIsLocked(false)
68  , myNeedInit(false)
69  {
70  if (!relaxedLoad(val))
71  {
72  myLock.lock();
73  myIsLocked = true;
74  if (!relaxedLoad(val))
75  myNeedInit = true;
76  }
77  }
78 
80  {
81  if (myIsLocked)
82  {
83  if (myNeedInit)
84  {
85  UT_ASSERT_P(myPendingValue);
86 
87  // Ensure that the data that myPendingValue refers to is
88  // written out to main memory before setting myValue.
89  SYSstoreFence();
90 
91  relaxedStore(myValue, TraitT::release(myPendingValue));
92 
93  // NOTE: LockT::unlock also does a store fence before
94  // unlocking, which ensures that myValue is written out to
95  // main memory before the lock is unlocked. If it didn't,
96  // the next thread might read myValue of 0 and try to
97  // initialize it again. The store fence above is also
98  // needed.
99  }
100  myLock.unlock();
101  }
102  }
103 
105 
106  GetT getValue() const
107  {
108  if (myPendingValue)
109  return TraitT::get(myPendingValue);
110 
111  GetT v = relaxedLoad(myValue);
112 
113  // This load fence is to ensure that any side effects of allocation
114  // in another thread, including values in the heap itself, are not
115  // speculatively read before the read of myValue. Also, some places
116  // do more than allocate a single item pointed to by v, especially
117  // for cases with UT_DoubleLock<bool>, so those count as side
118  // effects here.
119  SYSloadFence();
120 
121  return v;
122  }
124  {
125  UT_ASSERT_P(myNeedInit);
126  TraitT::move(myPendingValue, val);
127  }
128 
129  /// Abort writing back out to the val passed in the constructor upon
130  /// destruction.
131  void abort()
132  {
133  myNeedInit = false;
134  }
135 
136 private:
137  template <typename Y>
138  class ValueTrait
139  {
140  public:
141  using GetT = Y;
142  using SetT = Y;
143 
144  static Y release(Y &v) { return v; }
145  static GetT get(const Y &v) { return v; }
146  static void move(Y &dst, const Y &src) { dst = src; }
147  };
148  template <typename Y, typename DT>
149  class ValueTrait<UT_UniquePtr<Y, DT>>
150  {
151  using PtrT = UT_UniquePtr<Y, DT>;
152  public:
153  using GetT = Y*;
154  using SetT = PtrT &&;
155 
156  static GetT release(PtrT &v) { return v.release(); }
157  static GetT get(const PtrT &v) { return v.get(); }
158  static void move(PtrT &dst, PtrT &src) { dst.reset(src.release()); }
159  };
160  template <typename Y, typename DT>
161  class ValueTrait<UT_UniquePtr<Y[], DT>>
162  {
163  using PtrT = UT_UniquePtr<Y[], DT>;
164  public:
165  using GetT = Y*;
166  using SetT = PtrT &&;
167 
168  static GetT release(PtrT &v) { return v.release(); }
169  static GetT get(const PtrT &v) { return v.get(); }
170  static void move(PtrT &dst, PtrT &src) { dst.reset(src.release()); }
171  };
172 
173  static GetT relaxedLoad(const volatile ValueT &ptr)
174  {
175  const volatile GetT *addr
176  = reinterpret_cast<const volatile GetT *>(&ptr);
177  return *static_cast<const volatile GetT *>(addr);
178  }
179  static void relaxedStore(volatile ValueT &ptr, GetT src)
180  {
181  volatile GetT *addr = reinterpret_cast<volatile GetT *>(&ptr);
182  *static_cast<volatile GetT *>(addr) = src;
183  }
184 
185 private:
186  LockT &myLock;
187  volatile ValueT &myValue;
188  ValueT myPendingValue;
189  bool myIsLocked;
190  bool myNeedInit;
191 };
192 
193 #endif
194 
typename TraitT::SetT SetT
Definition: UT_DoubleLock.h:60
const GLdouble * v
Definition: glcorearb.h:837
#define SYSloadFence()
std::unique_ptr< T, Deleter > UT_UniquePtr
A smart pointer for unique ownership of dynamically allocated objects.
Definition: UT_UniquePtr.h:39
#define UT_ASSERT_P(ZZ)
Definition: UT_Assert.h:155
#define UT_NON_COPYABLE(CLASS)
Define deleted copy constructor and assignment operator inside a class.
GetT getValue() const
typename TraitT::GetT GetT
Definition: UT_DoubleLock.h:59
auto get(const UT_ARTIterator< T > &it) -> decltype(it.key())
Definition: UT_ARTMap.h:1073
#define SYSstoreFence()
GLenum GLenum dst
Definition: glcorearb.h:1793
UT_DoubleLock(LockT &lock, volatile ValueT &val)
Definition: UT_DoubleLock.h:63
auto ptr(T p) -> const void *
Definition: format.h:2448
GLuint GLfloat * val
Definition: glcorearb.h:1608
void setValue(SetT val)
GLenum src
Definition: glcorearb.h:1793