mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-08-28 00:00:11 +02:00
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:
co-authored by
Eliza Weisman
Alice Ryhl
parent
0783797520
commit
02cbe4591b
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user