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 #ifndef UTIL_MUTEX_H_ 6 #define UTIL_MUTEX_H_ 7 8 /* 9 * A simple mutex wrapper, supporting locks and read-write locks. 10 * You should assume the locks are *not* re-entrant. 11 */ 12 13 #ifdef _WIN32 14 // Requires Windows Vista or Windows Server 2008 at minimum. 15 #if defined(WINVER) && WINVER >= 0x0600 16 #define MUTEX_IS_WIN32_SRWLOCK 17 #endif 18 #else 19 #ifndef _POSIX_C_SOURCE 20 #define _POSIX_C_SOURCE 200809L 21 #endif 22 #include <unistd.h> 23 #if defined(_POSIX_READER_WRITER_LOCKS) && _POSIX_READER_WRITER_LOCKS > 0 24 #define MUTEX_IS_PTHREAD_RWLOCK 25 #endif 26 #endif 27 28 #if defined(MUTEX_IS_WIN32_SRWLOCK) 29 #include <windows.h> 30 typedef SRWLOCK MutexType; 31 #elif defined(MUTEX_IS_PTHREAD_RWLOCK) 32 #include <pthread.h> 33 #include <stdlib.h> 34 typedef pthread_rwlock_t MutexType; 35 #else 36 #include <mutex> 37 typedef std::mutex MutexType; 38 #endif 39 40 namespace re2 { 41 42 class Mutex { 43 public: 44 inline Mutex(); 45 inline ~Mutex(); 46 inline void Lock(); // Block if needed until free then acquire exclusively 47 inline void Unlock(); // Release a lock acquired via Lock() 48 // Note that on systems that don't support read-write locks, these may 49 // be implemented as synonyms to Lock() and Unlock(). So you can use 50 // these for efficiency, but don't use them anyplace where being able 51 // to do shared reads is necessary to avoid deadlock. 52 inline void ReaderLock(); // Block until free or shared then acquire a share 53 inline void ReaderUnlock(); // Release a read share of this Mutex WriterLock()54 inline void WriterLock() { Lock(); } // Acquire an exclusive lock WriterUnlock()55 inline void WriterUnlock() { Unlock(); } // Release a lock from WriterLock() 56 57 private: 58 MutexType mutex_; 59 60 // Catch the error of writing Mutex when intending MutexLock. 61 Mutex(Mutex *ignored); 62 63 Mutex(const Mutex&) = delete; 64 Mutex& operator=(const Mutex&) = delete; 65 }; 66 67 #if defined(MUTEX_IS_WIN32_SRWLOCK) 68 Mutex()69Mutex::Mutex() { InitializeSRWLock(&mutex_); } ~Mutex()70Mutex::~Mutex() { } Lock()71void Mutex::Lock() { AcquireSRWLockExclusive(&mutex_); } Unlock()72void Mutex::Unlock() { ReleaseSRWLockExclusive(&mutex_); } ReaderLock()73void Mutex::ReaderLock() { AcquireSRWLockShared(&mutex_); } ReaderUnlock()74void Mutex::ReaderUnlock() { ReleaseSRWLockShared(&mutex_); } 75 76 #elif defined(MUTEX_IS_PTHREAD_RWLOCK) 77 78 #define SAFE_PTHREAD(fncall) \ 79 do { \ 80 if ((fncall) != 0) abort(); \ 81 } while (0) 82 Mutex()83Mutex::Mutex() { SAFE_PTHREAD(pthread_rwlock_init(&mutex_, NULL)); } ~Mutex()84Mutex::~Mutex() { SAFE_PTHREAD(pthread_rwlock_destroy(&mutex_)); } Lock()85void Mutex::Lock() { SAFE_PTHREAD(pthread_rwlock_wrlock(&mutex_)); } Unlock()86void Mutex::Unlock() { SAFE_PTHREAD(pthread_rwlock_unlock(&mutex_)); } ReaderLock()87void Mutex::ReaderLock() { SAFE_PTHREAD(pthread_rwlock_rdlock(&mutex_)); } ReaderUnlock()88void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock(&mutex_)); } 89 90 #undef SAFE_PTHREAD 91 92 #else 93 Mutex()94Mutex::Mutex() { } ~Mutex()95Mutex::~Mutex() { } Lock()96void Mutex::Lock() { mutex_.lock(); } Unlock()97void Mutex::Unlock() { mutex_.unlock(); } ReaderLock()98void Mutex::ReaderLock() { Lock(); } // C++11 doesn't have std::shared_mutex. ReaderUnlock()99void Mutex::ReaderUnlock() { Unlock(); } 100 101 #endif 102 103 // -------------------------------------------------------------------------- 104 // Some helper classes 105 106 // MutexLock(mu) acquires mu when constructed and releases it when destroyed. 107 class MutexLock { 108 public: MutexLock(Mutex * mu)109 explicit MutexLock(Mutex *mu) : mu_(mu) { mu_->Lock(); } ~MutexLock()110 ~MutexLock() { mu_->Unlock(); } 111 private: 112 Mutex * const mu_; 113 114 MutexLock(const MutexLock&) = delete; 115 MutexLock& operator=(const MutexLock&) = delete; 116 }; 117 118 // ReaderMutexLock and WriterMutexLock do the same, for rwlocks 119 class ReaderMutexLock { 120 public: ReaderMutexLock(Mutex * mu)121 explicit ReaderMutexLock(Mutex *mu) : mu_(mu) { mu_->ReaderLock(); } ~ReaderMutexLock()122 ~ReaderMutexLock() { mu_->ReaderUnlock(); } 123 private: 124 Mutex * const mu_; 125 126 ReaderMutexLock(const ReaderMutexLock&) = delete; 127 ReaderMutexLock& operator=(const ReaderMutexLock&) = delete; 128 }; 129 130 class WriterMutexLock { 131 public: WriterMutexLock(Mutex * mu)132 explicit WriterMutexLock(Mutex *mu) : mu_(mu) { mu_->WriterLock(); } ~WriterMutexLock()133 ~WriterMutexLock() { mu_->WriterUnlock(); } 134 private: 135 Mutex * const mu_; 136 137 WriterMutexLock(const WriterMutexLock&) = delete; 138 WriterMutexLock& operator=(const WriterMutexLock&) = delete; 139 }; 140 141 // Catch bug where variable name is omitted, e.g. MutexLock (&mu); 142 #define MutexLock(x) static_assert(false, "MutexLock declaration missing variable name") 143 #define ReaderMutexLock(x) static_assert(false, "ReaderMutexLock declaration missing variable name") 144 #define WriterMutexLock(x) static_assert(false, "WriterMutexLock declaration missing variable name") 145 146 } // namespace re2 147 148 #endif // UTIL_MUTEX_H_ 149