![]() |
RTBKit
0.9
Open-source framework to create real-time ad bidding systems.
|
00001 /* rcu_protected.h -*- C++ -*- 00002 Jeremy Barnes, 12 April 2012 00003 Copyright (c) 2012 Datacratic. All rights reserved. 00004 00005 Building blocks for RCU protected data structures. 00006 */ 00007 00008 #ifndef __mmap__rcu_protected_h__ 00009 #define __mmap__rcu_protected_h__ 00010 00011 #include "gc_lock.h" 00012 #include "jml/utils/unnamed_bool.h" 00013 #include "jml/arch/atomic_ops.h" 00014 00015 namespace Datacratic { 00016 00017 template<typename T> 00018 struct RcuLocked { 00019 RcuLocked(T * ptr = 0, GcLock * lock = 0) 00020 : ptr(ptr), lock(lock) 00021 { 00022 if (lock) 00023 lock->lockShared(); 00024 } 00025 00027 template<typename T2> 00028 RcuLocked(T * ptr, RcuLocked<T2> && other) 00029 : ptr(ptr), lock(other.lock) 00030 { 00031 other.lock = 0; 00032 } 00033 00035 template<typename T2> 00036 RcuLocked(T * ptr, const RcuLocked<T2> & other) 00037 : ptr(ptr), lock(other.lock) 00038 { 00039 if (lock) 00040 lock->lockShared(); 00041 } 00042 00043 template<typename T2> 00044 RcuLocked(RcuLocked<T2> && other) 00045 : ptr(other.ptr), lock(other.lock) 00046 { 00047 other.lock = 0; 00048 } 00049 00050 RcuLocked & operator = (RcuLocked && other) 00051 { 00052 unlock(); 00053 lock = other.lock; 00054 ptr = other.ptr; 00055 return *this; 00056 } 00057 00058 template<typename T2> 00059 RcuLocked & operator = (RcuLocked<T2> && other) 00060 { 00061 unlock(); 00062 lock = other.lock; 00063 ptr = other.ptr; 00064 return *this; 00065 } 00066 00067 ~RcuLocked() 00068 { 00069 unlock(); 00070 } 00071 00072 void unlock() 00073 { 00074 if (lock) { 00075 lock->unlockShared(); 00076 lock = 0; 00077 } 00078 } 00079 00080 T * ptr; 00081 GcLock * lock; 00082 00083 operator T * () const 00084 { 00085 return ptr; 00086 } 00087 00088 T * operator -> () const 00089 { 00090 if (!ptr) 00091 throw ML::Exception("dereferencing null RCUResult"); 00092 return ptr; 00093 } 00094 00095 T & operator * () const 00096 { 00097 if (!ptr) 00098 throw ML::Exception("dereferencing null RCUResult"); 00099 return *ptr; 00100 } 00101 }; 00102 00103 template<typename T> 00104 struct RcuProtected { 00105 T * val; 00106 GcLock * lock; 00107 00108 template<typename... Args> 00109 RcuProtected(GcLock & lock, Args&&... args) 00110 : val(new T(std::forward<Args>(args)...)), lock(&lock) 00111 { 00112 //ExcAssert(this->lock); 00113 } 00114 00115 RcuProtected(T * val, GcLock & lock) 00116 : val(val), lock(&lock) 00117 { 00118 //ExcAssert(this->lock); 00119 } 00120 00121 RcuProtected(RcuProtected && other) 00122 : val(other.val), lock(other.lock) 00123 { 00124 //ExcAssert(this->lock); 00125 other.val = 0; 00126 } 00127 00128 RcuProtected & operator = (RcuProtected && other) 00129 { 00130 auto toDelete = val; 00131 val = other.val; 00132 lock = other.lock; 00133 other.val = 0; 00134 lock->deferDelete(toDelete); 00135 //ExcAssert(lock); 00136 return *this; 00137 } 00138 00139 ~RcuProtected() 00140 { 00141 lock->deferDelete(val); 00142 val = 0; 00143 } 00144 00145 JML_IMPLEMENT_OPERATOR_BOOL(val); 00146 00147 RcuLocked<T> operator () () 00148 { 00149 //ExcAssert(lock); 00150 return RcuLocked<T>(val, lock); 00151 } 00152 00153 RcuLocked<const T> operator () () const 00154 { 00155 //ExcAssert(lock); 00156 return RcuLocked<const T>(val, lock); 00157 } 00158 00159 void replace(T * newVal, bool defer = true) 00160 { 00161 T * toDelete = ML::atomic_xchg(val, newVal); 00162 if (toDelete) { 00163 ExcAssertNotEqual(toDelete, val); 00164 if (defer) lock->deferDelete(toDelete); 00165 else { 00166 lock->visibleBarrier(); 00167 delete toDelete; 00168 } 00169 } 00170 } 00171 00172 bool cmp_xchg(RcuLocked<T> & current, std::auto_ptr<T> & newValue, 00173 bool defer = true) 00174 { 00175 T * currentVal = current.ptr; 00176 if (ML::cmp_xchg(val, currentVal, newValue.get())) { 00177 ExcAssertNotEqual(currentVal, val); 00178 if (currentVal) { 00179 if (defer) 00180 lock->deferDelete(currentVal); 00181 else { 00182 lock->visibleBarrier(); 00183 delete currentVal; 00184 } 00185 } 00186 newValue.release(); 00187 current.ptr = val; 00188 return true; 00189 } 00190 return false; 00191 } 00192 00193 private: 00194 // Don't allow copy semantics (use RcuProtectedCopyable for that). Just 00195 // move semantics are OK. 00196 RcuProtected(); 00197 RcuProtected(const RcuProtected & other); 00198 void operator = (const RcuProtected & other); 00199 }; 00200 00201 template<typename T> 00202 struct RcuProtectedCopyable : public RcuProtected<T> { 00203 00204 using RcuProtected<T>::val; 00205 using RcuProtected<T>::lock; 00206 using RcuProtected<T>::operator (); 00207 using RcuProtected<T>::replace; 00208 00209 template<typename... Args> 00210 RcuProtectedCopyable(GcLock & lock, Args&&... args) 00211 : RcuProtected<T>(lock, std::forward<Args>(args)...) 00212 { 00213 } 00214 00215 RcuProtectedCopyable(const RcuProtectedCopyable & other) 00216 : RcuProtected<T>(new T(*other()), *other.lock) 00217 { 00218 } 00219 00220 RcuProtectedCopyable(RcuProtectedCopyable && other) 00221 : RcuProtected<T>(static_cast<RcuProtected<T> &&>(other)) 00222 { 00223 } 00224 00225 RcuProtectedCopyable & operator = (const RcuProtectedCopyable & other) 00226 { 00227 //ExcAssert(lock); 00228 auto toDelete = val; 00229 lock = other.lock; 00230 val = new T(*other()); 00231 if (toDelete) lock->deferDelete(toDelete); 00232 return *this; 00233 } 00234 00235 RcuProtectedCopyable & operator = (RcuProtectedCopyable && other) 00236 { 00237 //ExcAssert(lock); 00238 auto toDelete = val; 00239 lock = other.lock; 00240 val = other.val; 00241 other.val = 0; 00242 if (toDelete) lock->deferDelete(toDelete); 00243 return *this; 00244 } 00245 00246 }; 00247 00248 } // namespace Datacratic 00249 00250 #endif /* __mmap__rcu_protected_h__ */ 00251 00252