summaryrefslogtreecommitdiff
path: root/tests/future.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tests/future.rs')
-rw-r--r--tests/future.rs65
1 files changed, 65 insertions, 0 deletions
diff --git a/tests/future.rs b/tests/future.rs
new file mode 100644
index 0000000..3895946
--- /dev/null
+++ b/tests/future.rs
@@ -0,0 +1,65 @@
+#![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<MockWaker>) };
+ 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<MockWaker>) };
+ 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);
+ });
+}