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