Index: third_party/google_benchmark/src/mutex.h |
diff --git a/third_party/google_benchmark/src/mutex.h b/third_party/google_benchmark/src/mutex.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..5f461d05a0c64781bcd08ce380e6cfce1ecab3ad |
--- /dev/null |
+++ b/third_party/google_benchmark/src/mutex.h |
@@ -0,0 +1,155 @@ |
+#ifndef BENCHMARK_MUTEX_H_ |
+#define BENCHMARK_MUTEX_H_ |
+ |
+#include <condition_variable> |
+#include <mutex> |
+ |
+#include "check.h" |
+ |
+// Enable thread safety attributes only with clang. |
+// The attributes can be safely erased when compiling with other compilers. |
+#if defined(HAVE_THREAD_SAFETY_ATTRIBUTES) |
+#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) |
+#else |
+#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op |
+#endif |
+ |
+#define CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(capability(x)) |
+ |
+#define SCOPED_CAPABILITY THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable) |
+ |
+#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x)) |
+ |
+#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x)) |
+ |
+#define ACQUIRED_BEFORE(...) \ |
+ THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__)) |
+ |
+#define ACQUIRED_AFTER(...) \ |
+ THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__)) |
+ |
+#define REQUIRES(...) \ |
+ THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__)) |
+ |
+#define REQUIRES_SHARED(...) \ |
+ THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__)) |
+ |
+#define ACQUIRE(...) \ |
+ THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__)) |
+ |
+#define ACQUIRE_SHARED(...) \ |
+ THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__)) |
+ |
+#define RELEASE(...) \ |
+ THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__)) |
+ |
+#define RELEASE_SHARED(...) \ |
+ THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__)) |
+ |
+#define TRY_ACQUIRE(...) \ |
+ THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__)) |
+ |
+#define TRY_ACQUIRE_SHARED(...) \ |
+ THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__)) |
+ |
+#define EXCLUDES(...) THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__)) |
+ |
+#define ASSERT_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x)) |
+ |
+#define ASSERT_SHARED_CAPABILITY(x) \ |
+ THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x)) |
+ |
+#define RETURN_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x)) |
+ |
+#define NO_THREAD_SAFETY_ANALYSIS \ |
+ THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis) |
+ |
+namespace benchmark { |
+ |
+typedef std::condition_variable Condition; |
+ |
+// NOTE: Wrappers for std::mutex and std::unique_lock are provided so that |
+// we can annotate them with thread safety attributes and use the |
+// -Wthread-safety warning with clang. The standard library types cannot be |
+// used directly because they do not provided the required annotations. |
+class CAPABILITY("mutex") Mutex { |
+ public: |
+ Mutex() {} |
+ |
+ void lock() ACQUIRE() { mut_.lock(); } |
+ void unlock() RELEASE() { mut_.unlock(); } |
+ std::mutex& native_handle() { return mut_; } |
+ |
+ private: |
+ std::mutex mut_; |
+}; |
+ |
+class SCOPED_CAPABILITY MutexLock { |
+ typedef std::unique_lock<std::mutex> MutexLockImp; |
+ |
+ public: |
+ MutexLock(Mutex& m) ACQUIRE(m) : ml_(m.native_handle()) {} |
+ ~MutexLock() RELEASE() {} |
+ MutexLockImp& native_handle() { return ml_; } |
+ |
+ private: |
+ MutexLockImp ml_; |
+}; |
+ |
+class Barrier { |
+ public: |
+ Barrier(int num_threads) : running_threads_(num_threads) {} |
+ |
+ // Called by each thread |
+ bool wait() EXCLUDES(lock_) { |
+ bool last_thread = false; |
+ { |
+ MutexLock ml(lock_); |
+ last_thread = createBarrier(ml); |
+ } |
+ if (last_thread) phase_condition_.notify_all(); |
+ return last_thread; |
+ } |
+ |
+ void removeThread() EXCLUDES(lock_) { |
+ MutexLock ml(lock_); |
+ --running_threads_; |
+ if (entered_ != 0) phase_condition_.notify_all(); |
+ } |
+ |
+ private: |
+ Mutex lock_; |
+ Condition phase_condition_; |
+ int running_threads_; |
+ |
+ // State for barrier management |
+ int phase_number_ = 0; |
+ int entered_ = 0; // Number of threads that have entered this barrier |
+ |
+ // Enter the barrier and wait until all other threads have also |
+ // entered the barrier. Returns iff this is the last thread to |
+ // enter the barrier. |
+ bool createBarrier(MutexLock& ml) REQUIRES(lock_) { |
+ CHECK_LT(entered_, running_threads_); |
+ entered_++; |
+ if (entered_ < running_threads_) { |
+ // Wait for all threads to enter |
+ int phase_number_cp = phase_number_; |
+ auto cb = [this, phase_number_cp]() { |
+ return this->phase_number_ > phase_number_cp || |
+ entered_ == running_threads_; // A thread has aborted in error |
+ }; |
+ phase_condition_.wait(ml.native_handle(), cb); |
+ if (phase_number_ > phase_number_cp) return false; |
+ // else (running_threads_ == entered_) and we are the last thread. |
+ } |
+ // Last thread has reached the barrier |
+ phase_number_++; |
+ entered_ = 0; |
+ return true; |
+ } |
+}; |
+ |
+} // end namespace benchmark |
+ |
+#endif // BENCHMARK_MUTEX_H_ |