• 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 #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()66 Mutex::Mutex()             { SAFE_PTHREAD(pthread_rwlock_init(&mutex_, NULL)); }
~Mutex()67 Mutex::~Mutex()            { SAFE_PTHREAD(pthread_rwlock_destroy(&mutex_)); }
Lock()68 void Mutex::Lock()         { SAFE_PTHREAD(pthread_rwlock_wrlock(&mutex_)); }
Unlock()69 void Mutex::Unlock()       { SAFE_PTHREAD(pthread_rwlock_unlock(&mutex_)); }
ReaderLock()70 void Mutex::ReaderLock()   { SAFE_PTHREAD(pthread_rwlock_rdlock(&mutex_)); }
ReaderUnlock()71 void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock(&mutex_)); }
72 
73 #undef SAFE_PTHREAD
74 
75 #else
76 
Mutex()77 Mutex::Mutex()             { }
~Mutex()78 Mutex::~Mutex()            { }
Lock()79 void Mutex::Lock()         { mutex_.lock(); }
Unlock()80 void Mutex::Unlock()       { mutex_.unlock(); }
ReaderLock()81 void Mutex::ReaderLock()   { Lock(); }  // C++11 doesn't have std::shared_mutex.
ReaderUnlock()82 void 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