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#error We really dont want to include pthread
25#include <pthread.h>
26#include <stdlib.h>
27typedef pthread_rwlock_t MutexType;
28#else
29#include <mutex>
30typedef std::mutex MutexType;
31#endif
32
33namespace re2 {
34
35class Mutex {
36 public:
37 inline Mutex();
38 inline ~Mutex();
39 inline void Lock(); // Block if needed until free then acquire exclusively
40 inline void Unlock(); // Release a lock acquired via Lock()
41 // Note that on systems that don't support read-write locks, these may
42 // be implemented as synonyms to Lock() and Unlock(). So you can use
43 // these for efficiency, but don't use them anyplace where being able
44 // to do shared reads is necessary to avoid deadlock.
45 inline void ReaderLock(); // Block until free or shared then acquire a share
46 inline void ReaderUnlock(); // Release a read share of this Mutex
47 inline void WriterLock() { Lock(); } // Acquire an exclusive lock
48 inline void WriterUnlock() { Unlock(); } // Release a lock from WriterLock()
49
50 private:
51 MutexType mutex_;
52
53 // Catch the error of writing Mutex when intending MutexLock.
54 Mutex(Mutex *ignored);
55
56 Mutex(const Mutex&) = delete;
57 Mutex& operator=(const Mutex&) = delete;
58};
59
60#if defined(MUTEX_IS_PTHREAD_RWLOCK)
61
62#define SAFE_PTHREAD(fncall) \
63 do { \
64 if ((fncall) != 0) abort(); \
65 } while (0)
66
67Mutex::Mutex() { SAFE_PTHREAD(pthread_rwlock_init(&mutex_, NULL)); }
68Mutex::~Mutex() { SAFE_PTHREAD(pthread_rwlock_destroy(&mutex_)); }
69void Mutex::Lock() { SAFE_PTHREAD(pthread_rwlock_wrlock(&mutex_)); }
70void Mutex::Unlock() { SAFE_PTHREAD(pthread_rwlock_unlock(&mutex_)); }
71void Mutex::ReaderLock() { SAFE_PTHREAD(pthread_rwlock_rdlock(&mutex_)); }
72void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock(&mutex_)); }
73
74#undef SAFE_PTHREAD
75
76#else
77
78Mutex::Mutex() { }
79Mutex::~Mutex() { }
80void Mutex::Lock() { mutex_.lock(); }
81void Mutex::Unlock() { mutex_.unlock(); }
82void Mutex::ReaderLock() { Lock(); } // C++11 doesn't have std::shared_mutex.
83void Mutex::ReaderUnlock() { Unlock(); }
84
85#endif
86
87// --------------------------------------------------------------------------
88// Some helper classes
89
90// MutexLock(mu) acquires mu when constructed and releases it when destroyed.
91class MutexLock {
92 public:
93 explicit MutexLock(Mutex *mu) : mu_(mu) { mu_->Lock(); }
94 ~MutexLock() { mu_->Unlock(); }
95 private:
96 Mutex * const mu_;
97
98 MutexLock(const MutexLock&) = delete;
99 MutexLock& operator=(const MutexLock&) = delete;
100};
101
102// ReaderMutexLock and WriterMutexLock do the same, for rwlocks
103class ReaderMutexLock {
104 public:
105 explicit ReaderMutexLock(Mutex *mu) : mu_(mu) { mu_->ReaderLock(); }
106 ~ReaderMutexLock() { mu_->ReaderUnlock(); }
107 private:
108 Mutex * const mu_;
109
110 ReaderMutexLock(const ReaderMutexLock&) = delete;
111 ReaderMutexLock& operator=(const ReaderMutexLock&) = delete;
112};
113
114class WriterMutexLock {
115 public:
116 explicit WriterMutexLock(Mutex *mu) : mu_(mu) { mu_->WriterLock(); }
117 ~WriterMutexLock() { mu_->WriterUnlock(); }
118 private:
119 Mutex * const mu_;
120
121 WriterMutexLock(const WriterMutexLock&) = delete;
122 WriterMutexLock& operator=(const WriterMutexLock&) = delete;
123};
124
125// Catch bug where variable name is omitted, e.g. MutexLock (&mu);
126#define MutexLock(x) static_assert(false, "MutexLock declaration missing variable name")
127#define ReaderMutexLock(x) static_assert(false, "ReaderMutexLock declaration missing variable name")
128#define WriterMutexLock(x) static_assert(false, "WriterMutexLock declaration missing variable name")
129
130} // namespace re2
131
132#endif // UTIL_MUTEX_H_
133