• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #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 
73 namespace benchmark {
74 
75 typedef 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.
81 class CAPABILITY("mutex") Mutex
82 {
83 public:
Mutex()84   Mutex() {}
85 
lock()86   void lock() ACQUIRE() { mut_.lock(); }
unlock()87   void unlock() RELEASE() { mut_.unlock(); }
native_handle()88   std::mutex& native_handle() {
89     return mut_;
90   }
91 private:
92   std::mutex mut_;
93 };
94 
95 
96 class SCOPED_CAPABILITY MutexLock
97 {
98   typedef std::unique_lock<std::mutex> MutexLockImp;
99 public:
MutexLock(Mutex & m)100   MutexLock(Mutex& m) ACQUIRE(m) : ml_(m.native_handle())
101   { }
RELEASE()102   ~MutexLock() RELEASE() {}
native_handle()103   MutexLockImp& native_handle() { return ml_; }
104 private:
105   MutexLockImp ml_;
106 };
107 
108 
109 class Notification
110 {
111 public:
Notification()112   Notification() : notified_yet_(false) { }
113 
WaitForNotification()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 
Notify()122   void Notify() EXCLUDES(mutex_) {
123     {
124       MutexLock lock(mutex_);
125       notified_yet_ = 1;
126     }
127     cv_.notify_all();
128   }
129 
130 private:
HasBeenNotified()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_
143