diff --git a/tokio/src/runtime/io/scheduled_io.rs b/tokio/src/runtime/io/scheduled_io.rs index 04d81fef0c8..6fa5c4e6533 100644 --- a/tokio/src/runtime/io/scheduled_io.rs +++ b/tokio/src/runtime/io/scheduled_io.rs @@ -210,8 +210,8 @@ impl ScheduledIo { pub(super) fn set_readiness(&self, tick: Tick, f: impl Fn(Ready) -> Ready) { let mut current = self.readiness.load(Acquire); - // The shutdown bit should not be set - debug_assert_eq!(0, SHUTDOWN.unpack(current)); + // If the io driver is shut down, then you are only allowed to clear readiness. + debug_assert!(SHUTDOWN.unpack(current) == 0 || matches!(tick, Tick::Clear(_))); loop { // Mask out the tick bits so that the modifying function doesn't see diff --git a/tokio/tests/io_async_fd.rs b/tokio/tests/io_async_fd.rs index 7abd592d9df..943b023ecb3 100644 --- a/tokio/tests/io_async_fd.rs +++ b/tokio/tests/io_async_fd.rs @@ -578,6 +578,23 @@ fn driver_shutdown_wakes_poll() { assert_err!(futures::executor::block_on(poll_writable(&afd_a))); } +#[test] +fn driver_shutdown_then_clear_readiness() { + let rt = rt(); + + let (a, _b) = socketpair(); + let afd_a = { + let _enter = rt.enter(); + AsyncFd::new(a).unwrap() + }; + + let mut write_ready = rt.block_on(afd_a.writable()).unwrap(); + + std::mem::drop(rt); + + write_ready.clear_ready(); +} + #[test] fn driver_shutdown_wakes_poll_race() { // TODO: make this a loom test