runtime: improve safety comments of Readiness<'_> (#7415)

Signed-off-by: ADD-SP <[email protected]>
Co-authored-by: Eliza Weisman <[email protected]>
Co-authored-by: Alice Ryhl <[email protected]>
This commit is contained in:
Qi
2025-07-07 19:04:08 +08:00
committed by GitHub
co-authored by Eliza Weisman Alice Ryhl
parent 0783797520
commit 02cbe4591b
+30 -14
View File
@@ -133,7 +133,7 @@ struct Waiter {
is_ready: bool, is_ready: bool,
/// Should never be `!Unpin`. /// Should never be `Unpin`.
_p: PhantomPinned, _p: PhantomPinned,
} }
@@ -165,7 +165,7 @@ enum State {
// //
// | shutdown | driver tick | readiness | // | shutdown | driver tick | readiness |
// |----------+-------------+-----------| // |----------+-------------+-----------|
// | 1 bit | 15 bits + 16 bits | // | 1 bit | 15 bits | 16 bits |
const READINESS: bit::Pack = bit::Pack::least_significant(16); const READINESS: bit::Pack = bit::Pack::least_significant(16);
@@ -429,9 +429,16 @@ impl Future for Readiness<'_> {
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
use std::sync::atomic::Ordering::SeqCst; use std::sync::atomic::Ordering::SeqCst;
let (scheduled_io, state, waiter) = unsafe { let (scheduled_io, state, waiter) = {
let me = self.get_unchecked_mut(); // Safety: `Self` is `!Unpin`
(&me.scheduled_io, &mut me.state, &me.waiter) //
// While we could use `pin_project!` to remove
// this unsafe block, there are already unsafe blocks here,
// so it wouldn't significantly ease the mental burden
// and would actually complicate the code.
// That's why we didn't use it.
let me = unsafe { self.get_unchecked_mut() };
(me.scheduled_io, &mut me.state, &me.waiter)
}; };
loop { loop {
@@ -482,10 +489,13 @@ impl Future for Readiness<'_> {
// Not ready even after locked, insert into list... // Not ready even after locked, insert into list...
// Safety: called while locked // Safety: Since the `waiter` is not in the intrusive list yet,
unsafe { // we have exclusive access to it. The Mutex ensures
(*waiter.get()).waker = Some(cx.waker().clone()); // that this modification is visible to other threads that
} // acquire the same Mutex.
let waker = unsafe { &mut (*waiter.get()).waker };
let old = waker.replace(cx.waker().clone());
debug_assert!(old.is_none(), "waker should be None at the first poll");
// Insert the waiter into the linked list // Insert the waiter into the linked list
// //
@@ -503,7 +513,9 @@ impl Future for Readiness<'_> {
let waiters = scheduled_io.waiters.lock(); let waiters = scheduled_io.waiters.lock();
// Safety: called while locked // Safety: With the lock held, we have exclusive access to
// the waiter. In other words, `ScheduledIo::wake()`
// cannot access the waiter concurrently.
let w = unsafe { &mut *waiter.get() }; let w = unsafe { &mut *waiter.get() };
if w.is_ready { if w.is_ready {
@@ -523,9 +535,6 @@ impl Future for Readiness<'_> {
drop(waiters); drop(waiters);
} }
State::Done => { State::Done => {
// Safety: State::Done means it is no longer shared
let w = unsafe { &mut *waiter.get() };
let curr = scheduled_io.readiness.load(Acquire); let curr = scheduled_io.readiness.load(Acquire);
let is_shutdown = SHUTDOWN.unpack(curr) != 0; let is_shutdown = SHUTDOWN.unpack(curr) != 0;
@@ -534,9 +543,16 @@ impl Future for Readiness<'_> {
// still didn't return `Poll::Ready`. // still didn't return `Poll::Ready`.
let tick = TICK.unpack(curr) as u8; let tick = TICK.unpack(curr) as u8;
// Safety: We don't need to acquire the lock here because
// 1. `State::Done`` means `waiter` is no longer shared,
// this means no concurrent access to `waiter` can happen
// at this point.
// 2. `waiter.interest` is never changed, this means
// no side effects need to be synchronized by the lock.
let interest = unsafe { (*waiter.get()).interest };
// The readiness state could have been cleared in the meantime, // The readiness state could have been cleared in the meantime,
// but we allow the returned ready set to be empty. // but we allow the returned ready set to be empty.
let ready = Ready::from_usize(READINESS.unpack(curr)).intersection(w.interest); let ready = Ready::from_usize(READINESS.unpack(curr)).intersection(interest);
return Poll::Ready(ReadyEvent { return Poll::Ready(ReadyEvent {
tick, tick,