![]() |
RTBKit
0.9
Open-source framework to create real-time ad bidding systems.
|
00001 /* gc_lock.h -*- C++ -*- 00002 Jeremy Barnes, 19 November 2011 00003 Copyright (c) 2011 Datacratic. All rights reserved. 00004 00005 "Lock" that works by deferring the destruction of objects into a garbage collection 00006 process which is only run when nothing could be using them. 00007 */ 00008 00009 #ifndef __mmap__gc_lock_h__ 00010 #define __mmap__gc_lock_h__ 00011 00012 #define GC_LOCK_DEBUG 0 00013 00014 #include "jml/utils/exc_assert.h" 00015 #include "jml/arch/atomic_ops.h" 00016 #include "jml/arch/thread_specific.h" 00017 #include <vector> 00018 00019 #if GC_LOCK_DEBUG 00020 # include <iostream> 00021 #endif 00022 00023 namespace Datacratic { 00024 00025 00026 00027 /*****************************************************************************/ 00028 /* GC LOCK BASE */ 00029 /*****************************************************************************/ 00030 00031 struct GcLockBase : public boost::noncopyable { 00032 00033 struct Deferred; 00034 struct DeferredList; 00035 00037 struct ThreadGcInfoEntry { 00038 ThreadGcInfoEntry() 00039 : inEpoch(-1), readLocked(0), writeLocked(0) 00040 { 00041 } 00042 00043 int inEpoch; // 0, 1, -1 = not in 00044 int readLocked; 00045 int writeLocked; 00046 00047 std::string print() const; 00048 }; 00049 00050 typedef ML::ThreadSpecificInstanceInfo<ThreadGcInfoEntry, GcLockBase> 00051 GcInfo; 00052 typedef typename GcInfo::PerThreadInfo ThreadGcInfo; 00053 00054 GcInfo gcInfo; 00055 00056 struct Data { 00057 Data(); 00058 Data(const Data & other); 00059 00060 Data & operator = (const Data & other); 00061 00062 typedef uint64_t q2 __attribute__((__vector_size__(16))); 00063 00064 volatile union { 00065 struct { 00066 int32_t epoch; 00067 int16_t in[2]; 00068 int32_t visibleEpoch; 00069 int32_t exclusive; 00070 }; 00071 struct { 00072 uint64_t bits; 00073 uint64_t bits2; 00074 }; 00075 struct { 00076 q2 q; 00077 }; 00078 } JML_ALIGNED(16); 00079 00080 int16_t inCurrent() const { return in[epoch & 1]; } 00081 int16_t inOld() const { return in[(epoch - 1)&1]; } 00082 00083 void setIn(int32_t epoch, int val) 00084 { 00085 //if (epoch != this->epoch && epoch + 1 != this->epoch) 00086 // throw ML::Exception("modifying wrong epoch"); 00087 in[epoch & 1] = val; 00088 } 00089 00090 void addIn(int32_t epoch, int val) 00091 { 00092 //if (epoch != this->epoch && epoch + 1 != this->epoch) 00093 // throw ML::Exception("modifying wrong epoch"); 00094 in[epoch & 1] += val; 00095 } 00096 00098 void validate() const; 00099 00103 bool calcVisibleEpoch(); 00104 00106 std::string print() const; 00107 00108 bool operator == (const Data & other) const 00109 { 00110 return bits == other.bits && bits2 == other.bits2; 00111 } 00112 00113 bool operator != (const Data & other) const 00114 { 00115 return ! operator == (other); 00116 } 00117 00118 } JML_ALIGNED(16); 00119 00120 Data* data; 00121 00122 Deferred * deferred; 00123 00134 bool updateData(Data & oldValue, Data & newValue); 00135 00137 void runDefers(); 00138 00142 std::vector<DeferredList *> checkDefers(); 00143 00144 void enterCS(ThreadGcInfoEntry * entry = 0); 00145 void exitCS(ThreadGcInfoEntry * entry = 0); 00146 void enterCSExclusive(ThreadGcInfoEntry * entry = 0); 00147 void exitCSExclusive(ThreadGcInfoEntry * entry = 0); 00148 00149 int myEpoch(GcInfo::PerThreadInfo * threadInfo = 0) const 00150 { 00151 return getEntry(threadInfo).inEpoch; 00152 } 00153 00154 int currentEpoch() const 00155 { 00156 return data->epoch; 00157 } 00158 00159 JML_ALWAYS_INLINE ThreadGcInfoEntry & 00160 getEntry(GcInfo::PerThreadInfo * info = 0) const 00161 { 00162 return *gcInfo.get(info); 00163 } 00164 00165 GcLockBase(); 00166 00167 virtual ~GcLockBase(); 00168 00170 virtual void unlink() = 0; 00171 00172 void lockShared(GcInfo::PerThreadInfo * info = 0) 00173 { 00174 ThreadGcInfoEntry & entry = getEntry(info); 00175 00176 if (!entry.readLocked && !entry.writeLocked) 00177 enterCS(&entry); 00178 00179 ++entry.readLocked; 00180 00181 #if GC_LOCK_DEBUG 00182 using namespace std; 00183 cerr << "lockShared " 00184 << this << " index " << index 00185 << ": now " << entry.print() << " data " 00186 << data->print() << endl; 00187 #endif 00188 } 00189 00190 void unlockShared(GcInfo::PerThreadInfo * info = 0) 00191 { 00192 ThreadGcInfoEntry & entry = getEntry(info); 00193 00194 if (entry.readLocked <= 0) 00195 throw ML::Exception("bad read lock nesting"); 00196 --entry.readLocked; 00197 if (!entry.readLocked && !entry.writeLocked) 00198 exitCS(&entry); 00199 00200 #if GC_LOCK_DEBUG 00201 using namespace std; 00202 cerr << "unlockShared " 00203 << this << " index " << index 00204 << ": now " << entry.print() << " data " 00205 << data->print() << endl; 00206 #endif 00207 } 00208 00209 int isLockedShared(GcInfo::PerThreadInfo * info = 0) const 00210 { 00211 ThreadGcInfoEntry & entry = getEntry(info); 00212 return entry.readLocked + entry.writeLocked; 00213 } 00214 00215 int lockedInEpoch(GcInfo::PerThreadInfo * info = 0) const 00216 { 00217 ThreadGcInfoEntry & entry = getEntry(info); 00218 return entry.inEpoch; 00219 } 00220 00221 void lockExclusive(GcInfo::PerThreadInfo * info = 0) 00222 { 00223 ThreadGcInfoEntry & entry = getEntry(info); 00224 00225 if (entry.readLocked) 00226 throw ML::Exception("can't acquire write lock with read lock held"); 00227 00228 if (!entry.writeLocked) 00229 enterCSExclusive(&entry); 00230 00231 ++entry.writeLocked; 00232 00233 #if GC_LOCK_DEBUG 00234 using namespace std; 00235 cerr << "lockExclusive " 00236 << this << " index " << index 00237 << ": now " << entry.print() << " data " 00238 << data->print() << endl; 00239 #endif 00240 } 00241 00242 void unlockExclusive(GcInfo::PerThreadInfo * info = 0) 00243 { 00244 ThreadGcInfoEntry & entry = getEntry(info); 00245 00246 if (entry.writeLocked <= 0) 00247 throw ML::Exception("bad write lock nesting"); 00248 --entry.writeLocked; 00249 if (!entry.writeLocked) 00250 exitCSExclusive(&entry); 00251 00252 #if GC_LOCK_DEBUG 00253 using namespace std; 00254 cerr << "unlockExclusive" 00255 << this << " index " << index 00256 << ": now " << entry.print() 00257 << " data " << data->print() << endl; 00258 #endif 00259 } 00260 00261 int isLockedExclusive(GcInfo::PerThreadInfo * info = 0) const 00262 { 00263 ThreadGcInfoEntry & entry = getEntry(info); 00264 return entry.writeLocked; 00265 } 00266 00267 struct SharedGuard { 00268 SharedGuard(GcLockBase & lock) 00269 : lock(lock) 00270 { 00271 lock.lockShared(); 00272 } 00273 00274 ~SharedGuard() 00275 { 00276 lock.unlockShared(); 00277 } 00278 00279 GcLockBase & lock; 00280 }; 00281 00282 struct ExclusiveGuard { 00283 ExclusiveGuard(GcLockBase & lock) 00284 : lock(lock) 00285 { 00286 lock.lockExclusive(); 00287 } 00288 00289 ~ExclusiveGuard() 00290 { 00291 lock.unlockExclusive(); 00292 } 00293 00294 GcLockBase & lock; 00295 }; 00296 00303 void visibleBarrier(); 00304 00311 void deferBarrier(); 00312 00313 void defer(boost::function<void ()> work); 00314 00315 typedef void (WorkFn1) (void *); 00316 typedef void (WorkFn2) (void *, void *); 00317 typedef void (WorkFn3) (void *, void *, void *); 00318 00319 void defer(void (work) (void *), void * arg); 00320 void defer(void (work) (void *, void *), void * arg1, void * arg2); 00321 void defer(void (work) (void *, void *, void *), void * arg1, void * arg2, void * arg3); 00322 00323 template<typename T> 00324 void defer(void (*work) (T *), T * arg) 00325 { 00326 defer((WorkFn1 *)work, (void *)arg); 00327 } 00328 00329 template<typename T> 00330 static void doDelete(T * arg) 00331 { 00332 delete arg; 00333 } 00334 00335 template<typename T> 00336 void deferDelete(T * toDelete) 00337 { 00338 if (!toDelete) return; 00339 defer(doDelete<T>, toDelete); 00340 } 00341 00342 template<typename... Args> 00343 void doDefer(void (fn) (Args...), Args...); 00344 00345 template<typename Fn, typename... Args> 00346 void deferBind(Fn fn, Args... args) 00347 { 00348 boost::function<void ()> bound = boost::bind<void>(fn, args...); 00349 this->defer(bound); 00350 } 00351 00352 void dump(); 00353 }; 00354 00355 00356 /*****************************************************************************/ 00357 /* GC LOCK */ 00358 /*****************************************************************************/ 00359 00362 struct GcLock : public GcLockBase 00363 { 00364 GcLock(); 00365 virtual ~GcLock(); 00366 00367 virtual void unlink(); 00368 00369 private: 00370 00371 Data localData; 00372 00373 }; 00374 00375 00376 /*****************************************************************************/ 00377 /* SHARED GC LOCK */ 00378 /*****************************************************************************/ 00379 00383 extern struct GcCreate {} GC_CREATE; 00384 extern struct GcOpen {} GC_OPEN; 00385 00386 00389 struct SharedGcLock : public GcLockBase 00390 { 00391 SharedGcLock(GcCreate, const std::string& name); 00392 SharedGcLock(GcOpen, const std::string& name); 00393 virtual ~SharedGcLock(); 00394 00396 virtual void unlink(); 00397 00398 private: 00399 00401 void doOpen(bool create); 00402 00403 std::string name; 00404 int fd; 00405 void* addr; 00406 00407 }; 00408 00409 } // namespace Datacratic 00410 00411 #endif /* __mmap__gc_lock_h__ */ 00412