benchmark
1.10.0
Toggle main menu visibility
Loading...
Searching...
No Matches
mutex.h
1
#ifndef BENCHMARK_MUTEX_H_
2
#define BENCHMARK_MUTEX_H_
3
4
#include <condition_variable>
5
#include <mutex>
6
7
#include "check.h"
8
9
// Enable thread safety attributes only with clang.
10
// The attributes can be safely erased when compiling with other compilers.
11
//
12
// Whether the annotations below are needed is a property of the compiler, not
13
// of the build: whoever compiles this may pass -Wthread-safety without saying
14
// so (Bazel's default toolchain adds it whenever the compiler accepts it), and
15
// the wrappers then get analyzed with their own annotations erased -- so
16
// Mutex::lock() is seen acquiring mut_ and never releasing it, which is an
17
// error wherever the standard library annotates std::mutex itself (libc++).
18
// Setting the macro from a build file cannot fix that in general, because the
19
// same build file also has to serve compilers that reject the attributes.
20
// Deciding it here keeps the two in step. A definition from the outside still
21
// wins.
22
#if !defined(HAVE_THREAD_SAFETY_ATTRIBUTES) && defined(__clang__)
23
#define HAVE_THREAD_SAFETY_ATTRIBUTES
24
#endif
25
26
#if defined(HAVE_THREAD_SAFETY_ATTRIBUTES)
27
#define THREAD_ANNOTATION_ATTRIBUTE_(x) __attribute__((x))
28
#else
29
#define THREAD_ANNOTATION_ATTRIBUTE_(x)
// no-op
30
#endif
31
32
#define CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE_(capability(x))
33
34
#define SCOPED_CAPABILITY THREAD_ANNOTATION_ATTRIBUTE_(scoped_lockable)
35
36
#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE_(guarded_by(x))
37
38
#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE_(pt_guarded_by(x))
39
40
#define ACQUIRED_BEFORE(...) \
41
THREAD_ANNOTATION_ATTRIBUTE_(acquired_before(__VA_ARGS__))
42
43
#define ACQUIRED_AFTER(...) \
44
THREAD_ANNOTATION_ATTRIBUTE_(acquired_after(__VA_ARGS__))
45
46
#define REQUIRES(...) \
47
THREAD_ANNOTATION_ATTRIBUTE_(requires_capability(__VA_ARGS__))
48
49
#define REQUIRES_SHARED(...) \
50
THREAD_ANNOTATION_ATTRIBUTE_(requires_shared_capability(__VA_ARGS__))
51
52
#define ACQUIRE(...) \
53
THREAD_ANNOTATION_ATTRIBUTE_(acquire_capability(__VA_ARGS__))
54
55
#define ACQUIRE_SHARED(...) \
56
THREAD_ANNOTATION_ATTRIBUTE_(acquire_shared_capability(__VA_ARGS__))
57
58
#define RELEASE(...) \
59
THREAD_ANNOTATION_ATTRIBUTE_(release_capability(__VA_ARGS__))
60
61
#define RELEASE_SHARED(...) \
62
THREAD_ANNOTATION_ATTRIBUTE_(release_shared_capability(__VA_ARGS__))
63
64
#define TRY_ACQUIRE(...) \
65
THREAD_ANNOTATION_ATTRIBUTE_(try_acquire_capability(__VA_ARGS__))
66
67
#define TRY_ACQUIRE_SHARED(...) \
68
THREAD_ANNOTATION_ATTRIBUTE_(try_acquire_shared_capability(__VA_ARGS__))
69
70
#define EXCLUDES(...) THREAD_ANNOTATION_ATTRIBUTE_(locks_excluded(__VA_ARGS__))
71
72
#define ASSERT_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE_(assert_capability(x))
73
74
#define ASSERT_SHARED_CAPABILITY(x) \
75
THREAD_ANNOTATION_ATTRIBUTE_(assert_shared_capability(x))
76
77
#define RETURN_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE_(lock_returned(x))
78
79
#define NO_THREAD_SAFETY_ANALYSIS \
80
THREAD_ANNOTATION_ATTRIBUTE_(no_thread_safety_analysis)
81
82
namespace
benchmark {
83
84
typedef
std::condition_variable Condition;
85
86
// NOTE: Wrappers for std::mutex and std::unique_lock are provided so that
87
// we can annotate them with thread safety attributes and use the
88
// -Wthread-safety warning with clang. The standard library types cannot be
89
// used directly because they do not provide the required annotations.
90
class
CAPABILITY(
"mutex"
) Mutex {
91
public
:
92
Mutex() {}
93
94
void
lock() ACQUIRE() { mut_.lock(); }
95
void
unlock() RELEASE() { mut_.unlock(); }
96
std::mutex& native_handle() {
return
mut_; }
97
98
private
:
99
std::mutex mut_;
100
};
101
102
class
SCOPED_CAPABILITY MutexLock {
103
typedef
std::unique_lock<std::mutex> MutexLockImp;
104
105
public
:
106
MutexLock(Mutex& m) ACQUIRE(m) : ml_(m.native_handle()) {}
107
~MutexLock() RELEASE() {}
108
MutexLockImp& native_handle() {
return
ml_; }
109
110
private
:
111
MutexLockImp ml_;
112
};
113
114
class
Barrier {
115
public
:
116
Barrier(
int
num_threads) : running_threads_(num_threads) {}
117
118
// Called by each thread
119
bool
wait() EXCLUDES(lock_) {
120
MutexLock
ml(lock_);
121
bool
last_thread = createBarrier(ml);
122
if
(last_thread) phase_condition_.notify_all();
123
return
last_thread;
124
}
125
126
void
removeThread() EXCLUDES(lock_) {
127
MutexLock
ml(lock_);
128
--running_threads_;
129
if
(entered_ != 0) phase_condition_.notify_all();
130
}
131
132
private
:
133
Mutex lock_;
134
Condition phase_condition_;
135
int
running_threads_;
136
137
// State for barrier management
138
int
phase_number_ = 0;
139
int
entered_ = 0;
// Number of threads that have entered this barrier
140
141
// Enter the barrier and wait until all other threads have also
142
// entered the barrier. Returns iff this is the last thread to
143
// enter the barrier.
144
bool
createBarrier(
MutexLock
& ml) REQUIRES(lock_) {
145
BM_CHECK_LT(entered_, running_threads_);
146
entered_++;
147
if
(entered_ < running_threads_) {
148
// Wait for all threads to enter
149
int
phase_number_cp = phase_number_;
150
auto
cb = [
this
, phase_number_cp]() {
151
return
this->phase_number_ > phase_number_cp ||
152
entered_ == running_threads_;
// A thread has aborted in error
153
};
154
phase_condition_.wait(ml.native_handle(), cb);
155
if
(phase_number_ > phase_number_cp)
return
false
;
156
// else (running_threads_ == entered_) and we are the last thread.
157
}
158
// Last thread has reached the barrier
159
phase_number_++;
160
entered_ = 0;
161
return
true
;
162
}
163
};
164
165
}
// end namespace benchmark
166
167
#endif
// BENCHMARK_MUTEX_H_
benchmark::MutexLock
Definition
mutex.h:102
src
mutex.h
Generated by
1.18.0