Home | History | Annotate | Download | only in util
      1 // Copyright 2007 The RE2 Authors.  All Rights Reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 /*
      6  * A simple mutex wrapper, supporting locks and read-write locks.
      7  * You should assume the locks are *not* re-entrant.
      8  */
      9 
     10 #ifndef RE2_UTIL_MUTEX_H_
     11 #define RE2_UTIL_MUTEX_H_
     12 
     13 namespace re2 {
     14 
     15 #define HAVE_PTHREAD 1
     16 #define HAVE_RWLOCK 1
     17 
     18 #if defined(NO_THREADS)
     19   typedef int MutexType;      // to keep a lock-count
     20 #elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
     21   // Needed for pthread_rwlock_*.  If it causes problems, you could take it
     22   // out, but then you'd have to unset HAVE_RWLOCK (at least on linux -- it
     23   // *does* cause problems for FreeBSD, or MacOSX, but isn't needed
     24   // for locking there.)
     25 # ifdef __linux__
     26 #   undef _XOPEN_SOURCE
     27 #   define _XOPEN_SOURCE 500  // may be needed to get the rwlock calls
     28 # endif
     29 # include <pthread.h>
     30   typedef pthread_rwlock_t MutexType;
     31 #elif defined(HAVE_PTHREAD)
     32 # include <pthread.h>
     33   typedef pthread_mutex_t MutexType;
     34 #elif defined(WIN32)
     35 # define WIN32_LEAN_AND_MEAN  // We only need minimal includes
     36 # ifdef GMUTEX_TRYLOCK
     37   // We need Windows NT or later for TryEnterCriticalSection().  If you
     38   // don't need that functionality, you can remove these _WIN32_WINNT
     39   // lines, and change TryLock() to assert(0) or something.
     40 #   ifndef _WIN32_WINNT
     41 #     define _WIN32_WINNT 0x0400
     42 #   endif
     43 # endif
     44 # include <windows.h>
     45   typedef CRITICAL_SECTION MutexType;
     46 #else
     47 # error Need to implement mutex.h for your architecture, or #define NO_THREADS
     48 #endif
     49 
     50 class Mutex {
     51  public:
     52   // Create a Mutex that is not held by anybody.
     53   inline Mutex();
     54 
     55   // Destructor
     56   inline ~Mutex();
     57 
     58   inline void Lock();    // Block if needed until free then acquire exclusively
     59   inline void Unlock();  // Release a lock acquired via Lock()
     60   inline bool TryLock(); // If free, Lock() and return true, else return false
     61   // Note that on systems that don't support read-write locks, these may
     62   // be implemented as synonyms to Lock() and Unlock().  So you can use
     63   // these for efficiency, but don't use them anyplace where being able
     64   // to do shared reads is necessary to avoid deadlock.
     65   inline void ReaderLock();   // Block until free or shared then acquire a share
     66   inline void ReaderUnlock(); // Release a read share of this Mutex
     67   inline void WriterLock() { Lock(); }     // Acquire an exclusive lock
     68   inline void WriterUnlock() { Unlock(); } // Release a lock from WriterLock()
     69   inline void AssertHeld() { }
     70 
     71  private:
     72   MutexType mutex_;
     73 
     74   // Catch the error of writing Mutex when intending MutexLock.
     75   Mutex(Mutex *ignored);
     76   // Disallow "evil" constructors
     77   Mutex(const Mutex&);
     78   void operator=(const Mutex&);
     79 };
     80 
     81 // Now the implementation of Mutex for various systems
     82 #if defined(NO_THREADS)
     83 
     84 // When we don't have threads, we can be either reading or writing,
     85 // but not both.  We can have lots of readers at once (in no-threads
     86 // mode, that's most likely to happen in recursive function calls),
     87 // but only one writer.  We represent this by having mutex_ be -1 when
     88 // writing and a number > 0 when reading (and 0 when no lock is held).
     89 //
     90 // In debug mode, we assert these invariants, while in non-debug mode
     91 // we do nothing, for efficiency.  That's why everything is in an
     92 // assert.
     93 #include <assert.h>
     94 
     95 Mutex::Mutex() : mutex_(0) { }
     96 Mutex::~Mutex()            { assert(mutex_ == 0); }
     97 void Mutex::Lock()         { assert(--mutex_ == -1); }
     98 void Mutex::Unlock()       { assert(mutex_++ == -1); }
     99 bool Mutex::TryLock()      { if (mutex_) return false; Lock(); return true; }
    100 void Mutex::ReaderLock()   { assert(++mutex_ > 0); }
    101 void Mutex::ReaderUnlock() { assert(mutex_-- > 0); }
    102 
    103 #elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
    104 
    105 #include <stdlib.h>      // for abort()
    106 #define SAFE_PTHREAD(fncall)  do { if ((fncall) != 0) abort(); } while (0)
    107 
    108 Mutex::Mutex()             { SAFE_PTHREAD(pthread_rwlock_init(&mutex_, NULL)); }
    109 Mutex::~Mutex()            { SAFE_PTHREAD(pthread_rwlock_destroy(&mutex_)); }
    110 void Mutex::Lock()         { SAFE_PTHREAD(pthread_rwlock_wrlock(&mutex_)); }
    111 void Mutex::Unlock()       { SAFE_PTHREAD(pthread_rwlock_unlock(&mutex_)); }
    112 bool Mutex::TryLock()      { return pthread_rwlock_trywrlock(&mutex_) == 0; }
    113 void Mutex::ReaderLock()   { SAFE_PTHREAD(pthread_rwlock_rdlock(&mutex_)); }
    114 void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock(&mutex_)); }
    115 
    116 #undef SAFE_PTHREAD
    117 
    118 #elif defined(HAVE_PTHREAD)
    119 
    120 #include <stdlib.h>      // for abort()
    121 #define SAFE_PTHREAD(fncall)  do { if ((fncall) != 0) abort(); } while (0)
    122 
    123 Mutex::Mutex()             { SAFE_PTHREAD(pthread_mutex_init(&mutex_, NULL)); }
    124 Mutex::~Mutex()            { SAFE_PTHREAD(pthread_mutex_destroy(&mutex_)); }
    125 void Mutex::Lock()         { SAFE_PTHREAD(pthread_mutex_lock(&mutex_)); }
    126 void Mutex::Unlock()       { SAFE_PTHREAD(pthread_mutex_unlock(&mutex_)); }
    127 bool Mutex::TryLock()      { return pthread_mutex_trylock(&mutex_) == 0; }
    128 void Mutex::ReaderLock()   { Lock(); }      // we don't have read-write locks
    129 void Mutex::ReaderUnlock() { Unlock(); }
    130 #undef SAFE_PTHREAD
    131 
    132 #elif defined(WIN32)
    133 
    134 Mutex::Mutex()             { InitializeCriticalSection(&mutex_); }
    135 Mutex::~Mutex()            { DeleteCriticalSection(&mutex_); }
    136 void Mutex::Lock()         { EnterCriticalSection(&mutex_); }
    137 void Mutex::Unlock()       { LeaveCriticalSection(&mutex_); }
    138 bool Mutex::TryLock()      { return TryEnterCriticalSection(&mutex_) != 0; }
    139 void Mutex::ReaderLock()   { Lock(); }      // we don't have read-write locks
    140 void Mutex::ReaderUnlock() { Unlock(); }
    141 
    142 #endif
    143 
    144 
    145 // --------------------------------------------------------------------------
    146 // Some helper classes
    147 
    148 // MutexLock(mu) acquires mu when constructed and releases it when destroyed.
    149 class MutexLock {
    150  public:
    151   explicit MutexLock(Mutex *mu) : mu_(mu) { mu_->Lock(); }
    152   ~MutexLock() { mu_->Unlock(); }
    153  private:
    154   Mutex * const mu_;
    155   // Disallow "evil" constructors
    156   MutexLock(const MutexLock&);
    157   void operator=(const MutexLock&);
    158 };
    159 
    160 // ReaderMutexLock and WriterMutexLock do the same, for rwlocks
    161 class ReaderMutexLock {
    162  public:
    163   explicit ReaderMutexLock(Mutex *mu) : mu_(mu) { mu_->ReaderLock(); }
    164   ~ReaderMutexLock() { mu_->ReaderUnlock(); }
    165  private:
    166   Mutex * const mu_;
    167   // Disallow "evil" constructors
    168   ReaderMutexLock(const ReaderMutexLock&);
    169   void operator=(const ReaderMutexLock&);
    170 };
    171 
    172 class WriterMutexLock {
    173  public:
    174   explicit WriterMutexLock(Mutex *mu) : mu_(mu) { mu_->WriterLock(); }
    175   ~WriterMutexLock() { mu_->WriterUnlock(); }
    176  private:
    177   Mutex * const mu_;
    178   // Disallow "evil" constructors
    179   WriterMutexLock(const WriterMutexLock&);
    180   void operator=(const WriterMutexLock&);
    181 };
    182 
    183 // Catch bug where variable name is omitted, e.g. MutexLock (&mu);
    184 #define MutexLock(x) COMPILE_ASSERT(0, mutex_lock_decl_missing_var_name)
    185 #define ReaderMutexLock(x) COMPILE_ASSERT(0, rmutex_lock_decl_missing_var_name)
    186 #define WriterMutexLock(x) COMPILE_ASSERT(0, wmutex_lock_decl_missing_var_name)
    187 
    188 // Provide safe way to declare and use global, linker-initialized mutex. Sigh.
    189 #ifdef HAVE_PTHREAD
    190 
    191 #define GLOBAL_MUTEX(name) \
    192 	static pthread_mutex_t (name) = PTHREAD_MUTEX_INITIALIZER
    193 #define GLOBAL_MUTEX_LOCK(name) \
    194 	pthread_mutex_lock(&(name))
    195 #define GLOBAL_MUTEX_UNLOCK(name) \
    196 	pthread_mutex_unlock(&(name))
    197 
    198 #else
    199 
    200 #define GLOBAL_MUTEX(name) \
    201 	static Mutex name
    202 #define GLOBAL_MUTEX_LOCK(name) \
    203 	name.Lock()
    204 #define GLOBAL_MUTEX_UNLOCK(name) \
    205 	name.Unlock()
    206 
    207 #endif
    208 
    209 }  // namespace re2
    210 
    211 #endif  /* #define RE2_UTIL_MUTEX_H_ */
    212