Home | History | Annotate | Download | only in src
      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 #if defined(HAVE_THREAD_SAFETY_ATTRIBUTES)
     12 #define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
     13 #else
     14 #define THREAD_ANNOTATION_ATTRIBUTE__(x)  // no-op
     15 #endif
     16 
     17 #define CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
     18 
     19 #define SCOPED_CAPABILITY THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
     20 
     21 #define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
     22 
     23 #define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
     24 
     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 
     55 #define EXCLUDES(...) THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
     56 
     57 #define ASSERT_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
     58 
     59 #define ASSERT_SHARED_CAPABILITY(x) \
     60   THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
     61 
     62 #define RETURN_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
     63 
     64 #define NO_THREAD_SAFETY_ANALYSIS \
     65   THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
     66 
     67 namespace benchmark {
     68 
     69 typedef 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.
     75 class CAPABILITY("mutex") Mutex {
     76  public:
     77   Mutex() {}
     78 
     79   void lock() ACQUIRE() { mut_.lock(); }
     80   void unlock() RELEASE() { mut_.unlock(); }
     81   std::mutex& native_handle() { return mut_; }
     82 
     83  private:
     84   std::mutex mut_;
     85 };
     86 
     87 class SCOPED_CAPABILITY MutexLock {
     88   typedef std::unique_lock<std::mutex> MutexLockImp;
     89 
     90  public:
     91   MutexLock(Mutex& m) ACQUIRE(m) : ml_(m.native_handle()) {}
     92   ~MutexLock() RELEASE() {}
     93   MutexLockImp& native_handle() { return ml_; }
     94 
     95  private:
     96   MutexLockImp ml_;
     97 };
     98 
     99 class Barrier {
    100  public:
    101   Barrier(int num_threads) : running_threads_(num_threads) {}
    102 
    103   // Called by each thread
    104   bool wait() EXCLUDES(lock_) {
    105     bool last_thread = false;
    106     {
    107       MutexLock ml(lock_);
    108       last_thread = createBarrier(ml);
    109     }
    110     if (last_thread) phase_condition_.notify_all();
    111     return last_thread;
    112   }
    113 
    114   void removeThread() EXCLUDES(lock_) {
    115     MutexLock ml(lock_);
    116     --running_threads_;
    117     if (entered_ != 0) phase_condition_.notify_all();
    118   }
    119 
    120  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   }
    151 };
    152 
    153 }  // end namespace benchmark
    154 
    155 #endif  // BENCHMARK_MUTEX_H_
    156