1 /* Copyright (c) 2007, Google Inc.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 * Author: Craig Silverstein.
33 * A simple mutex wrapper, supporting locks and read-write locks.
34 * You should assume the locks are *not* re-entrant.
36 * To use: you should define the following macros in your configure.ac:
39 * The latter is defined in ../autoconf.
41 * This class is meant to be internal-only, so it's defined in the
42 * global namespace. If you want to expose it, you'll want to move
43 * it to the Google namespace.
45 * NOTE: by default, we have #ifdef'ed out the TryLock() method.
46 * This is for two reasons:
47 * 1) TryLock() under Windows is a bit annoying (it requires a
48 * #define to be defined very early).
49 * 2) TryLock() is broken for NO_THREADS mode, at least in NDEBUG
51 * If you need TryLock(), and either these two caveats are not a
52 * problem for you, or you're willing to work around them, then
53 * feel free to #define GMUTEX_TRYLOCK, or to remove the #ifdefs
57 // TODO(hamaji): Probably we must provide way to ensure static mutexes are
58 // initialized before they are used.
59 // (Google3's NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX)
61 #ifndef GOOGLE_MUTEX_H__
62 #define GOOGLE_MUTEX_H__
64 #include "config.h" // to figure out pthreads support
65 #include "utilities.h" // to get OS_* macro
67 #if defined(NO_THREADS)
68 typedef int MutexType; // to keep a lock-count
69 #elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
70 // Needed for pthread_rwlock_*. If it causes problems, you could take it
71 // out, but then you'd have to unset HAVE_RWLOCK (at least on linux -- it
72 // *does* cause problems for FreeBSD, or MacOSX, but isn't needed
73 // for locking there.)
75 # define _XOPEN_SOURCE 500 // may be needed to get the rwlock calls
78 typedef pthread_rwlock_t MutexType;
79 #elif defined(HAVE_PTHREAD)
81 typedef pthread_mutex_t MutexType;
82 #elif defined(OS_WINDOWS)
83 # define WIN32_LEAN_AND_MEAN // We only need minimal includes
84 # ifdef GMUTEX_TRYLOCK
85 // We need Windows NT or later for TryEnterCriticalSection(). If you
86 // don't need that functionality, you can remove these _WIN32_WINNT
87 // lines, and change TryLock() to assert(0) or something.
89 # define _WIN32_WINNT 0x0400
92 // To avoid macro definition of ERROR.
95 typedef CRITICAL_SECTION MutexType;
97 # error Need to implement mutex.h for your architecture, or #define NO_THREADS
102 // Create a Mutex that is not held by anybody. This constructor is
103 // typically used for Mutexes allocated on the heap or the stack.
104 // See below for a recommendation for constructing global Mutex
111 inline void Lock(); // Block if needed until free then acquire exclusively
112 inline void Unlock(); // Release a lock acquired via Lock()
113 #ifdef GMUTEX_TRYLOCK
114 inline bool TryLock(); // If free, Lock() and return true, else return false
116 // Note that on systems that don't support read-write locks, these may
117 // be implemented as synonyms to Lock() and Unlock(). So you can use
118 // these for efficiency, but don't use them anyplace where being able
119 // to do shared reads is necessary to avoid deadlock.
120 inline void ReaderLock(); // Block until free or shared then acquire a share
121 inline void ReaderUnlock(); // Release a read share of this Mutex
122 inline void WriterLock() { Lock(); } // Acquire an exclusive lock
123 inline void WriterUnlock() { Unlock(); } // Release a lock from WriterLock()
125 // TODO(hamaji): Do nothing, implement correctly.
126 inline void AssertHeld() {}
131 // Catch the error of writing Mutex when intending MutexLock.
132 Mutex(Mutex *ignored) {}
133 // Disallow "evil" constructors
135 void operator=(const Mutex&);
138 // Now the implementation of Mutex for various systems
139 #if defined(NO_THREADS)
141 // When we don't have threads, we can be either reading or writing,
142 // but not both. We can have lots of readers at once (in no-threads
143 // mode, that's most likely to happen in recursive function calls),
144 // but only one writer. We represent this by having mutex_ be -1 when
145 // writing and a number > 0 when reading (and 0 when no lock is held).
147 // In debug mode, we assert these invariants, while in non-debug mode
148 // we do nothing, for efficiency. That's why everything is in an
152 Mutex::Mutex() : mutex_(0) { }
153 Mutex::~Mutex() { assert(mutex_ == 0); }
154 void Mutex::Lock() { assert(--mutex_ == -1); }
155 void Mutex::Unlock() { assert(mutex_++ == -1); }
156 #ifdef GMUTEX_TRYLOCK
157 bool Mutex::TryLock() { if (mutex_) return false; Lock(); return true; }
159 void Mutex::ReaderLock() { assert(++mutex_ > 0); }
160 void Mutex::ReaderUnlock() { assert(mutex_-- > 0); }
162 #elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
164 #include <stdlib.h> // for abort()
165 #define SAFE_PTHREAD(fncall) do { if ((fncall) != 0) abort(); } while (0)
167 Mutex::Mutex() { SAFE_PTHREAD(pthread_rwlock_init(&mutex_, NULL)); }
168 Mutex::~Mutex() { SAFE_PTHREAD(pthread_rwlock_destroy(&mutex_)); }
169 void Mutex::Lock() { SAFE_PTHREAD(pthread_rwlock_wrlock(&mutex_)); }
170 void Mutex::Unlock() { SAFE_PTHREAD(pthread_rwlock_unlock(&mutex_)); }
171 #ifdef GMUTEX_TRYLOCK
172 bool Mutex::TryLock() { return pthread_rwlock_trywrlock(&mutex_) == 0; }
174 void Mutex::ReaderLock() { SAFE_PTHREAD(pthread_rwlock_rdlock(&mutex_)); }
175 void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock(&mutex_)); }
178 #elif defined(HAVE_PTHREAD)
180 #include <stdlib.h> // for abort()
181 #define SAFE_PTHREAD(fncall) do { if ((fncall) != 0) abort(); } while (0)
183 Mutex::Mutex() { SAFE_PTHREAD(pthread_mutex_init(&mutex_, NULL)); }
184 Mutex::~Mutex() { SAFE_PTHREAD(pthread_mutex_destroy(&mutex_)); }
185 void Mutex::Lock() { SAFE_PTHREAD(pthread_mutex_lock(&mutex_)); }
186 void Mutex::Unlock() { SAFE_PTHREAD(pthread_mutex_unlock(&mutex_)); }
187 #ifdef GMUTEX_TRYLOCK
188 bool Mutex::TryLock() { return pthread_mutex_trylock(&mutex_) == 0; }
190 void Mutex::ReaderLock() { Lock(); } // we don't have read-write locks
191 void Mutex::ReaderUnlock() { Unlock(); }
196 Mutex::Mutex() { InitializeCriticalSection(&mutex_); }
197 Mutex::~Mutex() { DeleteCriticalSection(&mutex_); }
198 void Mutex::Lock() { EnterCriticalSection(&mutex_); }
199 void Mutex::Unlock() { LeaveCriticalSection(&mutex_); }
200 #ifdef GMUTEX_TRYLOCK
201 bool Mutex::TryLock() { return TryEnterCriticalSection(&mutex_) != 0; }
203 void Mutex::ReaderLock() { Lock(); } // we don't have read-write locks
204 void Mutex::ReaderUnlock() { Unlock(); }
209 // --------------------------------------------------------------------------
210 // Some helper classes
212 // MutexLock(mu) acquires mu when constructed and releases it when destroyed.
215 explicit MutexLock(Mutex *mu) : mu_(mu) { mu_->Lock(); }
216 ~MutexLock() { mu_->Unlock(); }
219 // Disallow "evil" constructors
220 MutexLock(const MutexLock&);
221 void operator=(const MutexLock&);
224 // ReaderMutexLock and WriterMutexLock do the same, for rwlocks
225 class ReaderMutexLock {
227 explicit ReaderMutexLock(Mutex *mu) : mu_(mu) { mu_->ReaderLock(); }
228 ~ReaderMutexLock() { mu_->ReaderUnlock(); }
231 // Disallow "evil" constructors
232 ReaderMutexLock(const ReaderMutexLock&);
233 void operator=(const ReaderMutexLock&);
236 class WriterMutexLock {
238 explicit WriterMutexLock(Mutex *mu) : mu_(mu) { mu_->WriterLock(); }
239 ~WriterMutexLock() { mu_->WriterUnlock(); }
242 // Disallow "evil" constructors
243 WriterMutexLock(const WriterMutexLock&);
244 void operator=(const WriterMutexLock&);
247 // Catch bug where variable name is omitted, e.g. MutexLock (&mu);
248 #define MutexLock(x) COMPILE_ASSERT(0, mutex_lock_decl_missing_var_name)
249 #define ReaderMutexLock(x) COMPILE_ASSERT(0, rmutex_lock_decl_missing_var_name)
250 #define WriterMutexLock(x) COMPILE_ASSERT(0, wmutex_lock_decl_missing_var_name)
252 #endif /* #define GOOGLE_MUTEX_H__ */