1*7330f729Sjoerg #ifndef BENCHMARK_MUTEX_H_ 2*7330f729Sjoerg #define BENCHMARK_MUTEX_H_ 3*7330f729Sjoerg 4*7330f729Sjoerg #include <condition_variable> 5*7330f729Sjoerg #include <mutex> 6*7330f729Sjoerg 7*7330f729Sjoerg #include "check.h" 8*7330f729Sjoerg 9*7330f729Sjoerg // Enable thread safety attributes only with clang. 10*7330f729Sjoerg // The attributes can be safely erased when compiling with other compilers. 11*7330f729Sjoerg #if defined(HAVE_THREAD_SAFETY_ATTRIBUTES) 12*7330f729Sjoerg #define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) 13*7330f729Sjoerg #else 14*7330f729Sjoerg #define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op 15*7330f729Sjoerg #endif 16*7330f729Sjoerg 17*7330f729Sjoerg #define CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(capability(x)) 18*7330f729Sjoerg 19*7330f729Sjoerg #define SCOPED_CAPABILITY THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable) 20*7330f729Sjoerg 21*7330f729Sjoerg #define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x)) 22*7330f729Sjoerg 23*7330f729Sjoerg #define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x)) 24*7330f729Sjoerg 25*7330f729Sjoerg #define ACQUIRED_BEFORE(...) \ 26*7330f729Sjoerg THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__)) 27*7330f729Sjoerg 28*7330f729Sjoerg #define ACQUIRED_AFTER(...) \ 29*7330f729Sjoerg THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__)) 30*7330f729Sjoerg 31*7330f729Sjoerg #define REQUIRES(...) \ 32*7330f729Sjoerg THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__)) 33*7330f729Sjoerg 34*7330f729Sjoerg #define REQUIRES_SHARED(...) \ 35*7330f729Sjoerg THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__)) 36*7330f729Sjoerg 37*7330f729Sjoerg #define ACQUIRE(...) \ 38*7330f729Sjoerg THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__)) 39*7330f729Sjoerg 40*7330f729Sjoerg #define ACQUIRE_SHARED(...) \ 41*7330f729Sjoerg THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__)) 42*7330f729Sjoerg 43*7330f729Sjoerg #define RELEASE(...) \ 44*7330f729Sjoerg THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__)) 45*7330f729Sjoerg 46*7330f729Sjoerg #define RELEASE_SHARED(...) \ 47*7330f729Sjoerg THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__)) 48*7330f729Sjoerg 49*7330f729Sjoerg #define TRY_ACQUIRE(...) \ 50*7330f729Sjoerg THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__)) 51*7330f729Sjoerg 52*7330f729Sjoerg #define TRY_ACQUIRE_SHARED(...) \ 53*7330f729Sjoerg THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__)) 54*7330f729Sjoerg 55*7330f729Sjoerg #define EXCLUDES(...) THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__)) 56*7330f729Sjoerg 57*7330f729Sjoerg #define ASSERT_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x)) 58*7330f729Sjoerg 59*7330f729Sjoerg #define ASSERT_SHARED_CAPABILITY(x) \ 60*7330f729Sjoerg THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x)) 61*7330f729Sjoerg 62*7330f729Sjoerg #define RETURN_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x)) 63*7330f729Sjoerg 64*7330f729Sjoerg #define NO_THREAD_SAFETY_ANALYSIS \ 65*7330f729Sjoerg THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis) 66*7330f729Sjoerg 67*7330f729Sjoerg namespace benchmark { 68*7330f729Sjoerg 69*7330f729Sjoerg typedef std::condition_variable Condition; 70*7330f729Sjoerg 71*7330f729Sjoerg // NOTE: Wrappers for std::mutex and std::unique_lock are provided so that 72*7330f729Sjoerg // we can annotate them with thread safety attributes and use the 73*7330f729Sjoerg // -Wthread-safety warning with clang. The standard library types cannot be 74*7330f729Sjoerg // used directly because they do not provided the required annotations. 75*7330f729Sjoerg class CAPABILITY("mutex") Mutex { 76*7330f729Sjoerg public: Mutex()77*7330f729Sjoerg Mutex() {} 78*7330f729Sjoerg lock()79*7330f729Sjoerg void lock() ACQUIRE() { mut_.lock(); } unlock()80*7330f729Sjoerg void unlock() RELEASE() { mut_.unlock(); } native_handle()81*7330f729Sjoerg std::mutex& native_handle() { return mut_; } 82*7330f729Sjoerg 83*7330f729Sjoerg private: 84*7330f729Sjoerg std::mutex mut_; 85*7330f729Sjoerg }; 86*7330f729Sjoerg 87*7330f729Sjoerg class SCOPED_CAPABILITY MutexLock { 88*7330f729Sjoerg typedef std::unique_lock<std::mutex> MutexLockImp; 89*7330f729Sjoerg 90*7330f729Sjoerg public: MutexLock(Mutex & m)91*7330f729Sjoerg MutexLock(Mutex& m) ACQUIRE(m) : ml_(m.native_handle()) {} RELEASE()92*7330f729Sjoerg ~MutexLock() RELEASE() {} native_handle()93*7330f729Sjoerg MutexLockImp& native_handle() { return ml_; } 94*7330f729Sjoerg 95*7330f729Sjoerg private: 96*7330f729Sjoerg MutexLockImp ml_; 97*7330f729Sjoerg }; 98*7330f729Sjoerg 99*7330f729Sjoerg class Barrier { 100*7330f729Sjoerg public: Barrier(int num_threads)101*7330f729Sjoerg Barrier(int num_threads) : running_threads_(num_threads) {} 102*7330f729Sjoerg 103*7330f729Sjoerg // Called by each thread wait()104*7330f729Sjoerg bool wait() EXCLUDES(lock_) { 105*7330f729Sjoerg bool last_thread = false; 106*7330f729Sjoerg { 107*7330f729Sjoerg MutexLock ml(lock_); 108*7330f729Sjoerg last_thread = createBarrier(ml); 109*7330f729Sjoerg } 110*7330f729Sjoerg if (last_thread) phase_condition_.notify_all(); 111*7330f729Sjoerg return last_thread; 112*7330f729Sjoerg } 113*7330f729Sjoerg removeThread()114*7330f729Sjoerg void removeThread() EXCLUDES(lock_) { 115*7330f729Sjoerg MutexLock ml(lock_); 116*7330f729Sjoerg --running_threads_; 117*7330f729Sjoerg if (entered_ != 0) phase_condition_.notify_all(); 118*7330f729Sjoerg } 119*7330f729Sjoerg 120*7330f729Sjoerg private: 121*7330f729Sjoerg Mutex lock_; 122*7330f729Sjoerg Condition phase_condition_; 123*7330f729Sjoerg int running_threads_; 124*7330f729Sjoerg 125*7330f729Sjoerg // State for barrier management 126*7330f729Sjoerg int phase_number_ = 0; 127*7330f729Sjoerg int entered_ = 0; // Number of threads that have entered this barrier 128*7330f729Sjoerg 129*7330f729Sjoerg // Enter the barrier and wait until all other threads have also 130*7330f729Sjoerg // entered the barrier. Returns iff this is the last thread to 131*7330f729Sjoerg // enter the barrier. createBarrier(MutexLock & ml)132*7330f729Sjoerg bool createBarrier(MutexLock& ml) REQUIRES(lock_) { 133*7330f729Sjoerg CHECK_LT(entered_, running_threads_); 134*7330f729Sjoerg entered_++; 135*7330f729Sjoerg if (entered_ < running_threads_) { 136*7330f729Sjoerg // Wait for all threads to enter 137*7330f729Sjoerg int phase_number_cp = phase_number_; 138*7330f729Sjoerg auto cb = [this, phase_number_cp]() { 139*7330f729Sjoerg return this->phase_number_ > phase_number_cp || 140*7330f729Sjoerg entered_ == running_threads_; // A thread has aborted in error 141*7330f729Sjoerg }; 142*7330f729Sjoerg phase_condition_.wait(ml.native_handle(), cb); 143*7330f729Sjoerg if (phase_number_ > phase_number_cp) return false; 144*7330f729Sjoerg // else (running_threads_ == entered_) and we are the last thread. 145*7330f729Sjoerg } 146*7330f729Sjoerg // Last thread has reached the barrier 147*7330f729Sjoerg phase_number_++; 148*7330f729Sjoerg entered_ = 0; 149*7330f729Sjoerg return true; 150*7330f729Sjoerg } 151*7330f729Sjoerg }; 152*7330f729Sjoerg 153*7330f729Sjoerg } // end namespace benchmark 154*7330f729Sjoerg 155*7330f729Sjoerg #endif // BENCHMARK_MUTEX_H_ 156