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 |