RTBKit  0.9
Open-source framework to create real-time ad bidding systems.
soa/gc/rcu_protected.h
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    
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator