blob: f37ec35b3a42bc68b4a79555860586a78ef2764b [file] [log] [blame]
Eric Fiselierb08d8b12016-07-19 23:07:03 +00001#ifndef BENCHMARK_MUTEX_H_
2#define BENCHMARK_MUTEX_H_
3
4#include <mutex>
5#include <condition_variable>
6
7// Enable thread safety attributes only with clang.
8// The attributes can be safely erased when compiling with other compilers.
9#if defined(HAVE_THREAD_SAFETY_ATTRIBUTES)
10#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
11#else
12#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
13#endif
14
15#define CAPABILITY(x) \
16 THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
17
18#define SCOPED_CAPABILITY \
19 THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
20
21#define GUARDED_BY(x) \
22 THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
23
24#define PT_GUARDED_BY(x) \
25 THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
26
27#define ACQUIRED_BEFORE(...) \
28 THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
29
30#define ACQUIRED_AFTER(...) \
31 THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
32
33#define REQUIRES(...) \
34 THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
35
36#define REQUIRES_SHARED(...) \
37 THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
38
39#define ACQUIRE(...) \
40 THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
41
42#define ACQUIRE_SHARED(...) \
43 THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
44
45#define RELEASE(...) \
46 THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
47
48#define RELEASE_SHARED(...) \
49 THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
50
51#define TRY_ACQUIRE(...) \
52 THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
53
54#define TRY_ACQUIRE_SHARED(...) \
55 THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
56
57#define EXCLUDES(...) \
58 THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
59
60#define ASSERT_CAPABILITY(x) \
61 THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
62
63#define ASSERT_SHARED_CAPABILITY(x) \
64 THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
65
66#define RETURN_CAPABILITY(x) \
67 THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
68
69#define NO_THREAD_SAFETY_ANALYSIS \
70 THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
71
72
73namespace benchmark {
74
75typedef std::condition_variable Condition;
76
77// NOTE: Wrappers for std::mutex and std::unique_lock are provided so that
78// we can annotate them with thread safety attributes and use the
79// -Wthread-safety warning with clang. The standard library types cannot be
80// used directly because they do not provided the required annotations.
81class CAPABILITY("mutex") Mutex
82{
83public:
84 Mutex() {}
85
86 void lock() ACQUIRE() { mut_.lock(); }
87 void unlock() RELEASE() { mut_.unlock(); }
88 std::mutex& native_handle() {
89 return mut_;
90 }
91private:
92 std::mutex mut_;
93};
94
95
96class SCOPED_CAPABILITY MutexLock
97{
98 typedef std::unique_lock<std::mutex> MutexLockImp;
99public:
100 MutexLock(Mutex& m) ACQUIRE(m) : ml_(m.native_handle())
101 { }
102 ~MutexLock() RELEASE() {}
103 MutexLockImp& native_handle() { return ml_; }
104private:
105 MutexLockImp ml_;
106};
107
108
109class Notification
110{
111public:
112 Notification() : notified_yet_(false) { }
113
114 void WaitForNotification() const EXCLUDES(mutex_) {
115 MutexLock m_lock(mutex_);
116 auto notified_fn = [this]() REQUIRES(mutex_) {
117 return this->HasBeenNotified();
118 };
119 cv_.wait(m_lock.native_handle(), notified_fn);
120 }
121
122 void Notify() EXCLUDES(mutex_) {
123 {
124 MutexLock lock(mutex_);
125 notified_yet_ = 1;
126 }
127 cv_.notify_all();
128 }
129
130private:
131 bool HasBeenNotified() const REQUIRES(mutex_) {
132 return notified_yet_;
133 }
134
135 mutable Mutex mutex_;
136 mutable std::condition_variable cv_;
137 bool notified_yet_ GUARDED_BY(mutex_);
138};
139
140} // end namespace benchmark
141
142#endif // BENCHMARK_MUTEX_H_