From 09ad928f2024d986fbae896c645f56ff3953f152 Mon Sep 17 00:00:00 2001
From: Martin Karsten <mkarsten@uwaterloo.ca>
Date: Fri, 29 Jun 2018 15:16:13 -0400
Subject: [PATCH] - rename BargingMutex to SpinMutex and add proper barging
 mutex without atomic spinning

---
 src/runtime/BlockingSync.h | 45 ++++++++++++++++++++++++++++++++++----
 src/testoptions.h          |  1 +
 2 files changed, 42 insertions(+), 4 deletions(-)

diff --git a/src/runtime/BlockingSync.h b/src/runtime/BlockingSync.h
index 8af41f0..1ba9d62 100644
--- a/src/runtime/BlockingSync.h
+++ b/src/runtime/BlockingSync.h
@@ -410,8 +410,43 @@ public:
   }
 };
 
-template<typename Semaphore, bool OwnerLock, size_t SpinStart, size_t SpinEnd>
+template<typename Lock, bool OwnerLock = false, typename BQ = BlockingQueue<Lock>>
 class BargingMutex {
+  Lock lock;
+  StackContext* owner;
+  BQ bq;
+
+protected:
+  bool internalAcquire(bool wait, const Time& timeout = Time::zero()) {
+    StackContext* cs = CurrStack();
+    for (;;) {
+      lock.acquire();
+      if (!owner) break;
+      if (owner == cs) { GENASSERT1(OwnerLock, FmtHex(owner)); break; }
+      if (!bq.block(lock, wait, timeout)) return false;
+    }
+    owner = cs;
+    lock.release();
+    return true;
+  }
+
+public:
+  BargingMutex() : owner(nullptr) {}
+  bool test() { return owner != nullptr; }
+
+  bool tryAcquire()                                { return internalAcquire(false); }
+  bool acquire(const Time& timeout = Time::zero()) { return internalAcquire(true, timeout); }
+
+  void release() {
+    ScopedLock<Lock> al(lock);
+    GENASSERT1(owner == CurrStack(), FmtHex(owner));
+    owner = nullptr;
+    bq.unblock();
+  }
+};
+
+template<typename Semaphore, bool OwnerLock, size_t SpinStart, size_t SpinEnd>
+class SpinMutex {
   StackContext* owner;
   Semaphore sem;
 
@@ -442,7 +477,7 @@ protected:
   }
 
 public:
-  BargingMutex() : owner(nullptr), sem(1) {}
+  SpinMutex() : owner(nullptr), sem(1) {}
   bool test() { return __atomic_load_n(&owner, __ATOMIC_RELAXED) != nullptr; }
 
   bool tryAcquire()                                { return internalAcquire(false); }
@@ -480,10 +515,12 @@ public:
 template<typename Lock>
 #if TESTING_MUTEX_FIFO
 class Mutex : public FifoMutex<Lock> {};
+#elif TESTING_MUTEX_BARGING
+class Mutex : public BargingMutex<Lock> {};
 #elif TESTING_MUTEX_SPIN
-class Mutex : public BargingMutex<Benaphore<BargingSemaphore<Lock>>, false, 4, 1024> {};
+class Mutex : public SpinMutex<Benaphore<BargingSemaphore<Lock>>, false, 4, 1024> {};
 #else
-class Mutex : public BargingMutex<Benaphore<BargingSemaphore<Lock>>, false, 1, 0> {};
+class Mutex : public SpinMutex<Benaphore<BargingSemaphore<Lock>>, false, 1, 0> {};
 #endif
 
 // simple blocking RW lock: release alternates; new readers block when writer waits -> no starvation
diff --git a/src/testoptions.h b/src/testoptions.h
index 93009a7..eaa907b 100644
--- a/src/testoptions.h
+++ b/src/testoptions.h
@@ -20,6 +20,7 @@
 //#define TESTING_BLOCKING_CONCURRENT   1 // using MPSC blocking semantics (no prio levels)
 //#define TESTING_IDLE_SPIN             128 // spin before idle/halt threshold
 //#define TESTING_MUTEX_FIFO            1 // use fifo/baton mutex
+//#define TESTING_MUTEX_BARGING         1 // use blocking/barging mutex
 //#define TESTING_MUTEX_SPIN            1 // spin before block in non-fifo mutex
 //#define TESTING_PLACEMENT_RR          1 // RR placement, instead of load-based staging
 #define TESTING_WAKE_CLUSTER          1 // try waking idle processor on cluster backlog
-- 
GitLab