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>
26typedef pthread_rwlock_t MutexType;
27#else
28#include <mutex>
29typedef std::mutex MutexType;
30#endif
31
32namespace re2 {
33
34class 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
46 inline void WriterLock() { Lock(); } // Acquire an exclusive lock
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
66Mutex::Mutex() { SAFE_PTHREAD(pthread_rwlock_init(&mutex_, NULL)); }
67Mutex::~Mutex() { SAFE_PTHREAD(pthread_rwlock_destroy(&mutex_)); }
68void Mutex::Lock() { SAFE_PTHREAD(pthread_rwlock_wrlock(&mutex_)); }
69void Mutex::Unlock() { SAFE_PTHREAD(pthread_rwlock_unlock(&mutex_)); }
70void Mutex::ReaderLock() { SAFE_PTHREAD(pthread_rwlock_rdlock(&mutex_)); }
71void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock(&mutex_)); }
72
73#undef SAFE_PTHREAD
74
75#else
76
77Mutex::Mutex() { }
78Mutex::~Mutex() { }
79void Mutex::Lock() { mutex_.lock(); }
80void Mutex::Unlock() { mutex_.unlock(); }
81void Mutex::ReaderLock() { Lock(); } // C++11 doesn't have std::shared_mutex.
82void 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.
90class MutexLock {
91 public:
92 explicit MutexLock(Mutex *mu) : mu_(mu) { mu_->Lock(); }
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
102class ReaderMutexLock {
103 public:
104 explicit ReaderMutexLock(Mutex *mu) : mu_(mu) { mu_->ReaderLock(); }
105 ~ReaderMutexLock() { mu_->ReaderUnlock(); }
106 private:
107 Mutex * const mu_;
108
109 ReaderMutexLock(const ReaderMutexLock&) = delete;
110 ReaderMutexLock& operator=(const ReaderMutexLock&) = delete;
111};
112
113class WriterMutexLock {
114 public:
115 explicit WriterMutexLock(Mutex *mu) : mu_(mu) { mu_->WriterLock(); }
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