+ DeterministicSchedule::afterSharedAccess(true);
+ return rv;
+ }
+
+ /** Read the value of the atomic variable without context switching */
+ T load_direct() const noexcept {
+ return data.load(std::memory_order_relaxed);
+ }
+};
+
+/**
+ * DeterministicMutex is a drop-in replacement of std::mutex that
+ * cooperates with DeterministicSchedule.
+ */
+struct DeterministicMutex {
+ std::mutex m;
+
+ DeterministicMutex() = default;
+ ~DeterministicMutex() = default;
+ DeterministicMutex(DeterministicMutex const&) = delete;
+ DeterministicMutex& operator=(DeterministicMutex const&) = delete;
+
+ void lock() {
+ FOLLY_TEST_DSCHED_VLOG(this << ".lock()");
+ while (!try_lock()) {
+ // Not calling m.lock() in order to avoid deadlock when the
+ // mutex m is held by another thread. The deadlock would be
+ // between the call to m.lock() and the lock holder's wait on
+ // its own tls_sem scheduling semaphore.
+ }
+ }
+
+ bool try_lock() {
+ DeterministicSchedule::beforeSharedAccess();
+ bool rv = m.try_lock();
+ FOLLY_TEST_DSCHED_VLOG(this << ".try_lock() -> " << rv);