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