Coverage Report

Created: 2023-03-02 15:38

/src/re2/util/mutex.h
Line
Count
Source (jump to first uncovered line)
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
#ifdef RE2_NO_THREADS
14
#include <assert.h>
15
#define MUTEX_IS_LOCK_COUNTER
16
#else
17
#ifdef _WIN32
18
// Requires Windows Vista or Windows Server 2008 at minimum.
19
#include <windows.h>
20
#if defined(WINVER) && WINVER >= 0x0600
21
#define MUTEX_IS_WIN32_SRWLOCK
22
#endif
23
#else
24
#ifndef _POSIX_C_SOURCE
25
#define _POSIX_C_SOURCE 200809L
26
#endif
27
#include <unistd.h>
28
#if defined(_POSIX_READER_WRITER_LOCKS) && _POSIX_READER_WRITER_LOCKS > 0
29
#define MUTEX_IS_PTHREAD_RWLOCK
30
#endif
31
#endif
32
#endif
33
34
#if defined(MUTEX_IS_LOCK_COUNTER)
35
typedef int MutexType;
36
#elif defined(MUTEX_IS_WIN32_SRWLOCK)
37
typedef SRWLOCK MutexType;
38
#elif defined(MUTEX_IS_PTHREAD_RWLOCK)
39
#include <pthread.h>
40
#include <stdlib.h>
41
typedef pthread_rwlock_t MutexType;
42
#else
43
#include <shared_mutex>
44
typedef std::shared_mutex MutexType;
45
#endif
46
47
namespace re2 {
48
49
class Mutex {
50
 public:
51
  inline Mutex();
52
  inline ~Mutex();
53
  inline void Lock();    // Block if needed until free then acquire exclusively
54
  inline void Unlock();  // Release a lock acquired via Lock()
55
  // Note that on systems that don't support read-write locks, these may
56
  // be implemented as synonyms to Lock() and Unlock().  So you can use
57
  // these for efficiency, but don't use them anyplace where being able
58
  // to do shared reads is necessary to avoid deadlock.
59
  inline void ReaderLock();   // Block until free or shared then acquire a share
60
  inline void ReaderUnlock(); // Release a read share of this Mutex
61
0
  inline void WriterLock() { Lock(); }     // Acquire an exclusive lock
62
0
  inline void WriterUnlock() { Unlock(); } // Release a lock from WriterLock()
63
64
 private:
65
  MutexType mutex_;
66
67
  // Catch the error of writing Mutex when intending MutexLock.
68
  Mutex(Mutex *ignored);
69
70
  Mutex(const Mutex&) = delete;
71
  Mutex& operator=(const Mutex&) = delete;
72
};
73
74
#if defined(MUTEX_IS_LOCK_COUNTER)
75
76
Mutex::Mutex()             : mutex_(0) { }
77
Mutex::~Mutex()            { assert(mutex_ == 0); }
78
void Mutex::Lock()         { assert(--mutex_ == -1); }
79
void Mutex::Unlock()       { assert(mutex_++ == -1); }
80
void Mutex::ReaderLock()   { assert(++mutex_ > 0); }
81
void Mutex::ReaderUnlock() { assert(mutex_-- > 0); }
82
83
#elif defined(MUTEX_IS_WIN32_SRWLOCK)
84
85
Mutex::Mutex()             : mutex_(SRWLOCK_INIT) { }
86
Mutex::~Mutex()            { }
87
void Mutex::Lock()         { AcquireSRWLockExclusive(&mutex_); }
88
void Mutex::Unlock()       { ReleaseSRWLockExclusive(&mutex_); }
89
void Mutex::ReaderLock()   { AcquireSRWLockShared(&mutex_); }
90
void Mutex::ReaderUnlock() { ReleaseSRWLockShared(&mutex_); }
91
92
#elif defined(MUTEX_IS_PTHREAD_RWLOCK)
93
94
#define SAFE_PTHREAD(fncall)    \
95
1.07M
  do {                          \
96
1.07M
    if ((fncall) != 0) abort(); \
97
1.07M
  } while (0)
98
99
87.2k
Mutex::Mutex()             { SAFE_PTHREAD(pthread_rwlock_init(&mutex_, NULL)); }
100
87.2k
Mutex::~Mutex()            { SAFE_PTHREAD(pthread_rwlock_destroy(&mutex_)); }
101
410k
void Mutex::Lock()         { SAFE_PTHREAD(pthread_rwlock_wrlock(&mutex_)); }
102
410k
void Mutex::Unlock()       { SAFE_PTHREAD(pthread_rwlock_unlock(&mutex_)); }
103
38.3k
void Mutex::ReaderLock()   { SAFE_PTHREAD(pthread_rwlock_rdlock(&mutex_)); }
104
38.3k
void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock(&mutex_)); }
105
106
#undef SAFE_PTHREAD
107
108
#else
109
110
Mutex::Mutex()             { }
111
Mutex::~Mutex()            { }
112
void Mutex::Lock()         { mutex_.lock(); }
113
void Mutex::Unlock()       { mutex_.unlock(); }
114
void Mutex::ReaderLock()   { mutex_.lock_shared(); }
115
void Mutex::ReaderUnlock() { mutex_.unlock_shared(); }
116
117
#endif
118
119
// --------------------------------------------------------------------------
120
// Some helper classes
121
122
// MutexLock(mu) acquires mu when constructed and releases it when destroyed.
123
class MutexLock {
124
 public:
125
410k
  explicit MutexLock(Mutex *mu) : mu_(mu) { mu_->Lock(); }
126
410k
  ~MutexLock() { mu_->Unlock(); }
127
 private:
128
  Mutex * const mu_;
129
130
  MutexLock(const MutexLock&) = delete;
131
  MutexLock& operator=(const MutexLock&) = delete;
132
};
133
134
// ReaderMutexLock and WriterMutexLock do the same, for rwlocks
135
class ReaderMutexLock {
136
 public:
137
0
  explicit ReaderMutexLock(Mutex *mu) : mu_(mu) { mu_->ReaderLock(); }
138
0
  ~ReaderMutexLock() { mu_->ReaderUnlock(); }
139
 private:
140
  Mutex * const mu_;
141
142
  ReaderMutexLock(const ReaderMutexLock&) = delete;
143
  ReaderMutexLock& operator=(const ReaderMutexLock&) = delete;
144
};
145
146
class WriterMutexLock {
147
 public:
148
0
  explicit WriterMutexLock(Mutex *mu) : mu_(mu) { mu_->WriterLock(); }
149
0
  ~WriterMutexLock() { mu_->WriterUnlock(); }
150
 private:
151
  Mutex * const mu_;
152
153
  WriterMutexLock(const WriterMutexLock&) = delete;
154
  WriterMutexLock& operator=(const WriterMutexLock&) = delete;
155
};
156
157
// Catch bug where variable name is omitted, e.g. MutexLock (&mu);
158
#define MutexLock(x) static_assert(false, "MutexLock declaration missing variable name")
159
#define ReaderMutexLock(x) static_assert(false, "ReaderMutexLock declaration missing variable name")
160
#define WriterMutexLock(x) static_assert(false, "WriterMutexLock declaration missing variable name")
161
162
}  // namespace re2
163
164
#endif  // UTIL_MUTEX_H_