Commit 536e20e8 authored by Kenton Varda's avatar Kenton Varda

Fix Windows lock->wait() not waking other waiters.

parent 0028d85c
...@@ -408,6 +408,28 @@ TEST(Mutex, WhenWithTimeoutPreciseTimingAfterInterrupt) { ...@@ -408,6 +408,28 @@ TEST(Mutex, WhenWithTimeoutPreciseTimingAfterInterrupt) {
KJ_FAIL_ASSERT("time not within expected bounds even after retries"); KJ_FAIL_ASSERT("time not within expected bounds even after retries");
} }
KJ_TEST("wait()s wake each other") {
MutexGuarded<uint> value(0);
{
kj::Thread thread([&]() {
auto lock = value.lockExclusive();
++*lock;
lock.wait([](uint value) { return value == 2; });
++*lock;
lock.wait([](uint value) { return value == 4; });
});
{
auto lock = value.lockExclusive();
lock.wait([](uint value) { return value == 1; });
++*lock;
lock.wait([](uint value) { return value == 3; });
++*lock;
}
}
}
TEST(Mutex, Lazy) { TEST(Mutex, Lazy) {
Lazy<uint> lazy; Lazy<uint> lazy;
volatile bool initStarted = false; volatile bool initStarted = false;
......
...@@ -447,13 +447,11 @@ void Mutex::lock(Exclusivity exclusivity) { ...@@ -447,13 +447,11 @@ void Mutex::lock(Exclusivity exclusivity) {
} }
} }
void Mutex::unlock(Exclusivity exclusivity) { void Mutex::wakeReadyWaiter() {
switch (exclusivity) { // Look for a waiter whose predicate is now evaluating true, and wake it. We wake no more than
case EXCLUSIVE: { // one waiter because only one waiter could get the lock anyway, and once it releases that lock
KJ_DEFER(ReleaseSRWLockExclusive(&coercedSrwLock)); // it will awake the next waiter if necessary.
// Check if there are any conditional waiters. Note we only do this when unlocking an
// exclusive lock since under a shared lock the state couldn't have changed.
auto nextWaiter = waitersHead; auto nextWaiter = waitersHead;
for (;;) { for (;;) {
KJ_IF_MAYBE(waiter, nextWaiter) { KJ_IF_MAYBE(waiter, nextWaiter) {
...@@ -477,6 +475,16 @@ void Mutex::unlock(Exclusivity exclusivity) { ...@@ -477,6 +475,16 @@ void Mutex::unlock(Exclusivity exclusivity) {
break; break;
} }
} }
}
void Mutex::unlock(Exclusivity exclusivity) {
switch (exclusivity) {
case EXCLUSIVE: {
KJ_DEFER(ReleaseSRWLockExclusive(&coercedSrwLock));
// Check if there are any conditional waiters. Note we only do this when unlocking an
// exclusive lock since under a shared lock the state couldn't have changed.
wakeReadyWaiter();
break; break;
} }
...@@ -530,6 +538,10 @@ void Mutex::wait(Predicate& predicate, Maybe<Duration> timeout) { ...@@ -530,6 +538,10 @@ void Mutex::wait(Predicate& predicate, Maybe<Duration> timeout) {
} }
while (!predicate.check()) { while (!predicate.check()) {
// SleepConditionVariableSRW() will temporarily release the lock, so we need to signal other
// waiters that are now ready.
wakeReadyWaiter();
if (SleepConditionVariableSRW(&coercedCondvar(waiter.condvar), &coercedSrwLock, sleepMs, 0)) { if (SleepConditionVariableSRW(&coercedCondvar(waiter.condvar), &coercedSrwLock, sleepMs, 0)) {
// Normal result. Continue loop to check predicate. // Normal result. Continue loop to check predicate.
} else { } else {
......
...@@ -133,6 +133,9 @@ private: ...@@ -133,6 +133,9 @@ private:
inline void addWaiter(Waiter& waiter); inline void addWaiter(Waiter& waiter);
inline void removeWaiter(Waiter& waiter); inline void removeWaiter(Waiter& waiter);
bool checkPredicate(Waiter& waiter); bool checkPredicate(Waiter& waiter);
#if _WIN32
void wakeReadyWaiter();
#endif
}; };
class Once { class Once {
......
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