blob: 5f461d05a0c64781bcd08ce380e6cfce1ecab3ad [file] [log] [blame]
Eric Fiselierb08d8b12016-07-19 23:07:03 +00001#ifndef BENCHMARK_MUTEX_H_
2#define BENCHMARK_MUTEX_H_
3
Eric Fiselierb08d8b12016-07-19 23:07:03 +00004#include <condition_variable>
Eric Fiselierfbc9ff22016-11-05 00:30:27 +00005#include <mutex>
6
7#include "check.h"
Eric Fiselierb08d8b12016-07-19 23:07:03 +00008
9// Enable thread safety attributes only with clang.
10// The attributes can be safely erased when compiling with other compilers.
11#if defined(HAVE_THREAD_SAFETY_ATTRIBUTES)
Eric Fiselierfbc9ff22016-11-05 00:30:27 +000012#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
Eric Fiselierb08d8b12016-07-19 23:07:03 +000013#else
Eric Fiselierfbc9ff22016-11-05 00:30:27 +000014#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
Eric Fiselierb08d8b12016-07-19 23:07:03 +000015#endif
16
Eric Fiselierfbc9ff22016-11-05 00:30:27 +000017#define CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
Eric Fiselierb08d8b12016-07-19 23:07:03 +000018
Eric Fiselierfbc9ff22016-11-05 00:30:27 +000019#define SCOPED_CAPABILITY THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
Eric Fiselierb08d8b12016-07-19 23:07:03 +000020
Eric Fiselierfbc9ff22016-11-05 00:30:27 +000021#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
Eric Fiselierb08d8b12016-07-19 23:07:03 +000022
Eric Fiselierfbc9ff22016-11-05 00:30:27 +000023#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
Eric Fiselierb08d8b12016-07-19 23:07:03 +000024
25#define ACQUIRED_BEFORE(...) \
26 THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
27
28#define ACQUIRED_AFTER(...) \
29 THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
30
31#define REQUIRES(...) \
32 THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
33
34#define REQUIRES_SHARED(...) \
35 THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
36
37#define ACQUIRE(...) \
38 THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
39
40#define ACQUIRE_SHARED(...) \
41 THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
42
43#define RELEASE(...) \
44 THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
45
46#define RELEASE_SHARED(...) \
47 THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
48
49#define TRY_ACQUIRE(...) \
50 THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
51
52#define TRY_ACQUIRE_SHARED(...) \
53 THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
54
Eric Fiselierfbc9ff22016-11-05 00:30:27 +000055#define EXCLUDES(...) THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
Eric Fiselierb08d8b12016-07-19 23:07:03 +000056
Eric Fiselierfbc9ff22016-11-05 00:30:27 +000057#define ASSERT_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
Eric Fiselierb08d8b12016-07-19 23:07:03 +000058
59#define ASSERT_SHARED_CAPABILITY(x) \
60 THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
61
Eric Fiselierfbc9ff22016-11-05 00:30:27 +000062#define RETURN_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
Eric Fiselierb08d8b12016-07-19 23:07:03 +000063
64#define NO_THREAD_SAFETY_ANALYSIS \
65 THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
66
Eric Fiselierb08d8b12016-07-19 23:07:03 +000067namespace benchmark {
68
69typedef std::condition_variable Condition;
70
71// NOTE: Wrappers for std::mutex and std::unique_lock are provided so that
72// we can annotate them with thread safety attributes and use the
73// -Wthread-safety warning with clang. The standard library types cannot be
74// used directly because they do not provided the required annotations.
Eric Fiselierfbc9ff22016-11-05 00:30:27 +000075class CAPABILITY("mutex") Mutex {
76 public:
Eric Fiselierb08d8b12016-07-19 23:07:03 +000077 Mutex() {}
78
79 void lock() ACQUIRE() { mut_.lock(); }
80 void unlock() RELEASE() { mut_.unlock(); }
Eric Fiselierfbc9ff22016-11-05 00:30:27 +000081 std::mutex& native_handle() { return mut_; }
82
83 private:
Eric Fiselierb08d8b12016-07-19 23:07:03 +000084 std::mutex mut_;
85};
86
Eric Fiselierfbc9ff22016-11-05 00:30:27 +000087class SCOPED_CAPABILITY MutexLock {
Eric Fiselierb08d8b12016-07-19 23:07:03 +000088 typedef std::unique_lock<std::mutex> MutexLockImp;
Eric Fiselierfbc9ff22016-11-05 00:30:27 +000089
90 public:
91 MutexLock(Mutex& m) ACQUIRE(m) : ml_(m.native_handle()) {}
Eric Fiselierb08d8b12016-07-19 23:07:03 +000092 ~MutexLock() RELEASE() {}
93 MutexLockImp& native_handle() { return ml_; }
Eric Fiselierfbc9ff22016-11-05 00:30:27 +000094
95 private:
Eric Fiselierb08d8b12016-07-19 23:07:03 +000096 MutexLockImp ml_;
97};
98
Eric Fiselierfbc9ff22016-11-05 00:30:27 +000099class Barrier {
100 public:
101 Barrier(int num_threads) : running_threads_(num_threads) {}
Eric Fiselierb08d8b12016-07-19 23:07:03 +0000102
Eric Fiselierfbc9ff22016-11-05 00:30:27 +0000103 // Called by each thread
104 bool wait() EXCLUDES(lock_) {
105 bool last_thread = false;
Eric Fiselierb08d8b12016-07-19 23:07:03 +0000106 {
Eric Fiselierfbc9ff22016-11-05 00:30:27 +0000107 MutexLock ml(lock_);
108 last_thread = createBarrier(ml);
Eric Fiselierb08d8b12016-07-19 23:07:03 +0000109 }
Eric Fiselierfbc9ff22016-11-05 00:30:27 +0000110 if (last_thread) phase_condition_.notify_all();
111 return last_thread;
Eric Fiselierb08d8b12016-07-19 23:07:03 +0000112 }
113
Eric Fiselierfbc9ff22016-11-05 00:30:27 +0000114 void removeThread() EXCLUDES(lock_) {
115 MutexLock ml(lock_);
116 --running_threads_;
117 if (entered_ != 0) phase_condition_.notify_all();
Eric Fiselierb08d8b12016-07-19 23:07:03 +0000118 }
119
Eric Fiselierfbc9ff22016-11-05 00:30:27 +0000120 private:
121 Mutex lock_;
122 Condition phase_condition_;
123 int running_threads_;
124
125 // State for barrier management
126 int phase_number_ = 0;
127 int entered_ = 0; // Number of threads that have entered this barrier
128
129 // Enter the barrier and wait until all other threads have also
130 // entered the barrier. Returns iff this is the last thread to
131 // enter the barrier.
132 bool createBarrier(MutexLock& ml) REQUIRES(lock_) {
133 CHECK_LT(entered_, running_threads_);
134 entered_++;
135 if (entered_ < running_threads_) {
136 // Wait for all threads to enter
137 int phase_number_cp = phase_number_;
138 auto cb = [this, phase_number_cp]() {
139 return this->phase_number_ > phase_number_cp ||
140 entered_ == running_threads_; // A thread has aborted in error
141 };
142 phase_condition_.wait(ml.native_handle(), cb);
143 if (phase_number_ > phase_number_cp) return false;
144 // else (running_threads_ == entered_) and we are the last thread.
145 }
146 // Last thread has reached the barrier
147 phase_number_++;
148 entered_ = 0;
149 return true;
150 }
Eric Fiselierb08d8b12016-07-19 23:07:03 +0000151};
152
Eric Fiselierfbc9ff22016-11-05 00:30:27 +0000153} // end namespace benchmark
Eric Fiselierb08d8b12016-07-19 23:07:03 +0000154
Eric Fiselierfbc9ff22016-11-05 00:30:27 +0000155#endif // BENCHMARK_MUTEX_H_