Skip to content

Commit a0d2de0

Browse files
committed
Fix clearing PARKED_WRITER_BIT after a timeout
This needs to be done while holding the queue lock to avoid missed wakeups when a concurrent unlock clears this bit. Fixes #465
1 parent 03b0192 commit a0d2de0

File tree

1 file changed

+9
-5
lines changed

1 file changed

+9
-5
lines changed

src/raw_rwlock.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,7 +1008,12 @@ impl RawRwLock {
10081008
state & READERS_MASK != 0 && state & WRITER_PARKED_BIT != 0
10091009
};
10101010
let before_sleep = || {};
1011-
let timed_out = |_, _| {};
1011+
let timed_out = |_, was_last_thread: bool| {
1012+
// Clear the parked bit while holding the queue lock. There can
1013+
// only be one thread parked (this one).
1014+
debug_assert!(was_last_thread);
1015+
self.state.fetch_and(!WRITER_PARKED_BIT, Ordering::Relaxed);
1016+
};
10121017
// SAFETY:
10131018
// * `addr` is an address we control.
10141019
// * `validate`/`timed_out` does not panic or call into any function of `parking_lot`.
@@ -1037,10 +1042,9 @@ impl RawRwLock {
10371042
// We need to release WRITER_BIT and revert back to
10381043
// our previous value. We also wake up any threads that
10391044
// might be waiting on WRITER_BIT.
1040-
let state = self.state.fetch_add(
1041-
prev_value.wrapping_sub(WRITER_BIT | WRITER_PARKED_BIT),
1042-
Ordering::Relaxed,
1043-
);
1045+
let state = self
1046+
.state
1047+
.fetch_add(prev_value.wrapping_sub(WRITER_BIT), Ordering::Relaxed);
10441048
if state & PARKED_BIT != 0 {
10451049
let callback = |_, result: UnparkResult| {
10461050
// Clear the parked bit if there no more parked threads

0 commit comments

Comments
 (0)