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