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