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