• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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()69 Mutex::Mutex()             { InitializeSRWLock(&mutex_); }
~Mutex()70 Mutex::~Mutex()            { }
Lock()71 void Mutex::Lock()         { AcquireSRWLockExclusive(&mutex_); }
Unlock()72 void Mutex::Unlock()       { ReleaseSRWLockExclusive(&mutex_); }
ReaderLock()73 void Mutex::ReaderLock()   { AcquireSRWLockShared(&mutex_); }
ReaderUnlock()74 void 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()83 Mutex::Mutex()             { SAFE_PTHREAD(pthread_rwlock_init(&mutex_, NULL)); }
~Mutex()84 Mutex::~Mutex()            { SAFE_PTHREAD(pthread_rwlock_destroy(&mutex_)); }
Lock()85 void Mutex::Lock()         { SAFE_PTHREAD(pthread_rwlock_wrlock(&mutex_)); }
Unlock()86 void Mutex::Unlock()       { SAFE_PTHREAD(pthread_rwlock_unlock(&mutex_)); }
ReaderLock()87 void Mutex::ReaderLock()   { SAFE_PTHREAD(pthread_rwlock_rdlock(&mutex_)); }
ReaderUnlock()88 void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock(&mutex_)); }
89 
90 #undef SAFE_PTHREAD
91 
92 #else
93 
Mutex()94 Mutex::Mutex()             { }
~Mutex()95 Mutex::~Mutex()            { }
Lock()96 void Mutex::Lock()         { mutex_.lock(); }
Unlock()97 void Mutex::Unlock()       { mutex_.unlock(); }
ReaderLock()98 void Mutex::ReaderLock()   { Lock(); }  // C++11 doesn't have std::shared_mutex.
ReaderUnlock()99 void 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