#![cfg(feature = "async")] use core::{future, mem, pin, task}; #[cfg(loom)] pub use loom::sync::{Arc, Mutex}; #[cfg(not(loom))] pub use std::sync::{Arc, Mutex}; mod helpers; use helpers::maybe_loom_model; #[test] fn multiple_receiver_polls_keeps_only_latest_waker() { #[derive(Default)] struct MockWaker { cloned: usize, dropped: usize, } fn clone_mock_waker(waker: *const ()) -> task::RawWaker { let mock_waker = unsafe { Arc::from_raw(waker as *const Mutex) }; mock_waker.lock().unwrap().cloned += 1; let new_waker = task::RawWaker::new(Arc::into_raw(mock_waker.clone()) as *const (), &VTABLE); mem::forget(mock_waker); new_waker } fn drop_mock_waker(waker: *const ()) { let mock_waker = unsafe { Arc::from_raw(waker as *const Mutex) }; mock_waker.lock().unwrap().dropped += 1; } const VTABLE: task::RawWakerVTable = task::RawWakerVTable::new(clone_mock_waker, |_| (), |_| (), drop_mock_waker); maybe_loom_model(|| { let mock_waker1 = Arc::new(Mutex::new(MockWaker::default())); let raw_waker1 = task::RawWaker::new(Arc::into_raw(mock_waker1.clone()) as *const (), &VTABLE); let waker1 = unsafe { task::Waker::from_raw(raw_waker1) }; let mut context1 = task::Context::from_waker(&waker1); let (_sender, mut receiver) = oneshot::channel::<()>(); let poll_result = future::Future::poll(pin::Pin::new(&mut receiver), &mut context1); assert_eq!(poll_result, task::Poll::Pending); assert_eq!(mock_waker1.lock().unwrap().cloned, 1); assert_eq!(mock_waker1.lock().unwrap().dropped, 0); let mock_waker2 = Arc::new(Mutex::new(MockWaker::default())); let raw_waker2 = task::RawWaker::new(Arc::into_raw(mock_waker2.clone()) as *const (), &VTABLE); let waker2 = unsafe { task::Waker::from_raw(raw_waker2) }; let mut context2 = task::Context::from_waker(&waker2); let poll_result = future::Future::poll(pin::Pin::new(&mut receiver), &mut context2); assert_eq!(poll_result, task::Poll::Pending); assert_eq!(mock_waker2.lock().unwrap().cloned, 1); assert_eq!(mock_waker2.lock().unwrap().dropped, 0); assert_eq!(mock_waker1.lock().unwrap().cloned, 1); assert_eq!(mock_waker1.lock().unwrap().dropped, 1); }); }