Skip to content

Commit 851c225

Browse files
committed
Transpose the two checks in RawLockFuture::poll
We originally check try_lock before test if opt_key is None. This commit changes its order. Doing so removes the need to deregister_waker when opt_key is None, therefore makes the hot path (un-contended case) faster. Signed-off-by: Gary Guo <[email protected]>
1 parent 7855b90 commit 851c225

File tree

1 file changed

+35
-20
lines changed

1 file changed

+35
-20
lines changed

src/sync/mutex.rs

+35-20
Original file line numberDiff line numberDiff line change
@@ -105,41 +105,56 @@ impl<'a> Future for RawLockFuture<'a> {
105105
type Output = ();
106106

107107
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
108-
if self.mutex.try_lock() {
109-
self.deregister_waker(true);
110-
Poll::Ready(())
111-
} else {
112-
let mut blocked = self.mutex.blocked.lock();
113-
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-
}
108+
match self.opt_key {
109+
None => {
110+
if self.mutex.try_lock() {
111+
Poll::Ready(())
112+
} else {
113+
let mut blocked = self.mutex.blocked.lock();
114+
115+
// Try locking again because it's possible the mutex got unlocked before
116+
// we acquire the lock of `blocked`.
117+
let state = self.mutex.state.fetch_or(LOCK | BLOCKED, Ordering::Relaxed);
118+
if state & LOCK == 0 {
119+
return Poll::Ready(());
120+
}
122121

123-
// Register the current task.
124-
match self.opt_key {
125-
None => {
122+
// Register the current task.
126123
// Insert a new entry into the list of blocked tasks.
127124
let w = cx.waker().clone();
128125
let key = blocked.insert(Some(w));
129126
self.opt_key = Some(key);
127+
128+
Poll::Pending
130129
}
131-
Some(key) => {
130+
}
131+
Some(key) => {
132+
if self.mutex.try_lock() {
133+
self.deregister_waker(true);
134+
Poll::Ready(())
135+
} else {
136+
let mut blocked = self.mutex.blocked.lock();
137+
138+
// Try locking again because it's possible the mutex got unlocked before
139+
// we acquire the lock of `blocked`. On this path we know we have BLOCKED
140+
// set, so don't bother to set it again.
141+
if self.mutex.try_lock() {
142+
std::mem::drop(blocked);
143+
self.deregister_waker(true);
144+
return Poll::Ready(());
145+
}
146+
132147
// There is already an entry in the list of blocked tasks. Just
133148
// reset the waker if it was removed.
134149
let opt_waker = unsafe { blocked.get(key) };
135150
if opt_waker.is_none() {
136151
let w = cx.waker().clone();
137152
*opt_waker = Some(w);
138153
}
154+
155+
Poll::Pending
139156
}
140157
}
141-
142-
Poll::Pending
143158
}
144159
}
145160
}

0 commit comments

Comments
 (0)