Skip to content

Commit fd6b4b5

Browse files
committed
Retry locking the mutex before touching waker list.
Moving the try_lock code to before touching the waker list is sound, because the waker list can only ever be accessed with `blocked` hold, so as long as we retry lock it while having `blocked` locked, we are okay. This code also set both LOCK and BLOCKED in the same atomic op. This has some performance improvements by touching the atomic variable 1 less time when inserting the entry. Signed-off-by: Gary Guo <[email protected]>
1 parent 3e690fb commit fd6b4b5

File tree

1 file changed

+10
-13
lines changed

1 file changed

+10
-13
lines changed

src/sync/mutex.rs

+10-13
Original file line numberDiff line numberDiff line change
@@ -111,13 +111,18 @@ impl<'a> Future for RawLockFuture<'a> {
111111
} else {
112112
let mut blocked = self.mutex.blocked.lock();
113113

114+
// Try locking again because it's possible the mutex got unlocked before
115+
// we acquire the lock of `blocked`.
116+
let state = self.mutex.state.fetch_or(LOCK | BLOCKED, Ordering::Relaxed);
117+
if state & LOCK == 0 {
118+
std::mem::drop(blocked);
119+
self.deregister_waker(true);
120+
return Poll::Ready(())
121+
}
122+
114123
// Register the current task.
115124
match self.opt_key {
116125
None => {
117-
if blocked.is_empty() {
118-
self.mutex.state.fetch_or(BLOCKED, Ordering::Relaxed);
119-
}
120-
121126
// Insert a new entry into the list of blocked tasks.
122127
let w = cx.waker().clone();
123128
let key = blocked.insert(Some(w));
@@ -134,15 +139,7 @@ impl<'a> Future for RawLockFuture<'a> {
134139
}
135140
}
136141

137-
// Try locking again because it's possible the mutex got unlocked just
138-
// before the current task was registered as a blocked task.
139-
if self.mutex.try_lock() {
140-
std::mem::drop(blocked);
141-
self.deregister_waker(true);
142-
Poll::Ready(())
143-
} else {
144-
Poll::Pending
145-
}
142+
Poll::Pending
146143
}
147144
}
148145
}

0 commit comments

Comments
 (0)