11#include " visibility.h"
22#include < atomic>
3+ #include < chrono>
34#include < mutex>
5+ #include < thread>
6+
7+
8+ // Not all supported targets implement the wait / notify instructions on
9+ // atomics. Provide simple spinning fallback for ones that don't.
10+ template <typename T>
11+ concept Waitable = requires (T t)
12+ {
13+ t.notify_all ();
14+ };
415
516/* *
617 * Lightweight spinlock that falls back to using the operating system's futex
@@ -20,6 +31,35 @@ class ThinLock
2031 };
2132 // The lock word
2233 std::atomic<LockState> lockWord;
34+
35+ // Call notify if it exists
36+ template <typename T>
37+ static void notify (T &atomic) requires (Waitable<T>)
38+ {
39+ atomic.notify_all ();
40+ }
41+
42+ // Simply ignore notify if we don't have one.
43+ template <typename T>
44+ static void notify (T &atomic) requires (!Waitable<T>)
45+ {
46+ }
47+
48+ // Wait if we have a wait method.
49+ template <typename T>
50+ static void wait (T &atomic, LockState expected) requires (Waitable<T>)
51+ {
52+ atomic.wait (expected);
53+ }
54+
55+ // Short sleep if we don't.
56+ template <typename T>
57+ static void wait (T &atomic, LockState expected) requires (!Waitable<T>)
58+ {
59+ using namespace std ::chrono_literals;
60+ std::this_thread::sleep_for (1ms);
61+ }
62+
2363 public:
2464 // Acquire the lock
2565 void lock ()
@@ -41,7 +81,7 @@ class ThinLock
4181 continue ;
4282 }
4383 }
44- lockWord. wait (LockState::LockedWithWaiters);
84+ wait (lockWord, LockState::LockedWithWaiters);
4585 }
4686 }
4787
@@ -51,7 +91,7 @@ class ThinLock
5191 auto old = lockWord.exchange (LockState::Unlocked);
5292 if (old == LockState::LockedWithWaiters)
5393 {
54- lockWord. notify_all ( );
94+ notify (lockWord );
5595 }
5696 }
5797
0 commit comments