Commit 566f0478 authored by Doron Roberts-Kedes's avatar Doron Roberts-Kedes Committed by Facebook Github Bot

DeterministicSchedule: Deschedule threads waiting to acquire DeterministicMutex

Summary: Eliminate spinlock behavior from DeterministicMutex::lock by descheduling threads waiting to acquire the mutex, and placing the thread local semaphore in a waitqueue for the mutex. The unlocking thread reschedules a single waiting thread if the workqueue is non empty.

Reviewed By: djwatson

Differential Revision: D8789304

fbshipit-source-id: 8ffe3e289c9abfe7515b678ff98f0cefef2461c0
parent a72a920c
...@@ -183,6 +183,22 @@ void DeterministicSchedule::clearAuxChk() { ...@@ -183,6 +183,22 @@ void DeterministicSchedule::clearAuxChk() {
aux_chk = nullptr; aux_chk = nullptr;
} }
void DeterministicSchedule::reschedule(sem_t* sem) {
auto sched = tls_sched;
if (sched) {
sched->sems_.push_back(sem);
}
}
sem_t* DeterministicSchedule::descheduleCurrentThread() {
auto sched = tls_sched;
if (sched) {
sched->sems_.erase(
std::find(sched->sems_.begin(), sched->sems_.end(), tls_sem));
}
return tls_sem;
}
sem_t* DeterministicSchedule::beforeThreadCreate() { sem_t* DeterministicSchedule::beforeThreadCreate() {
sem_t* s = new sem_t; sem_t* s = new sem_t;
sem_init(s, 0, 0); sem_init(s, 0, 0);
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <atomic> #include <atomic>
#include <functional> #include <functional>
#include <mutex> #include <mutex>
#include <queue>
#include <thread> #include <thread>
#include <unordered_set> #include <unordered_set>
#include <vector> #include <vector>
...@@ -182,6 +183,12 @@ class DeterministicSchedule : boost::noncopyable { ...@@ -182,6 +183,12 @@ class DeterministicSchedule : boost::noncopyable {
/** Clears the function set by setAuxChk */ /** Clears the function set by setAuxChk */
static void clearAuxChk(); static void clearAuxChk();
/** Remove the current thread's semaphore from sems_ */
static sem_t* descheduleCurrentThread();
/** Add sem back into sems_ */
static void reschedule(sem_t* sem);
private: private:
static FOLLY_TLS sem_t* tls_sem; static FOLLY_TLS sem_t* tls_sem;
static FOLLY_TLS DeterministicSchedule* tls_sched; static FOLLY_TLS DeterministicSchedule* tls_sched;
...@@ -453,6 +460,7 @@ struct DeterministicAtomic { ...@@ -453,6 +460,7 @@ struct DeterministicAtomic {
*/ */
struct DeterministicMutex { struct DeterministicMutex {
std::mutex m; std::mutex m;
std::queue<sem_t*> waiters_;
DeterministicMutex() = default; DeterministicMutex() = default;
~DeterministicMutex() = default; ~DeterministicMutex() = default;
...@@ -461,12 +469,17 @@ struct DeterministicMutex { ...@@ -461,12 +469,17 @@ struct DeterministicMutex {
void lock() { void lock() {
FOLLY_TEST_DSCHED_VLOG(this << ".lock()"); FOLLY_TEST_DSCHED_VLOG(this << ".lock()");
while (!try_lock()) { DeterministicSchedule::beforeSharedAccess();
// Not calling m.lock() in order to avoid deadlock when the while (!m.try_lock()) {
// mutex m is held by another thread. The deadlock would be sem_t* sem = DeterministicSchedule::descheduleCurrentThread();
// between the call to m.lock() and the lock holder's wait on if (sem) {
// its own tls_sem scheduling semaphore. waiters_.push(sem);
}
DeterministicSchedule::afterSharedAccess();
// Wait to be scheduled by unlock
DeterministicSchedule::beforeSharedAccess();
} }
DeterministicSchedule::afterSharedAccess();
} }
bool try_lock() { bool try_lock() {
...@@ -480,6 +493,13 @@ struct DeterministicMutex { ...@@ -480,6 +493,13 @@ struct DeterministicMutex {
void unlock() { void unlock() {
FOLLY_TEST_DSCHED_VLOG(this << ".unlock()"); FOLLY_TEST_DSCHED_VLOG(this << ".unlock()");
m.unlock(); m.unlock();
DeterministicSchedule::beforeSharedAccess();
if (!waiters_.empty()) {
sem_t* sem = waiters_.front();
DeterministicSchedule::reschedule(sem);
waiters_.pop();
}
DeterministicSchedule::afterSharedAccess();
} }
}; };
} // namespace test } // namespace test
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment