diff options
author | Zahari Dichev <zaharidichev@gmail.com> | 2020-11-16 22:49:35 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-11-16 12:49:35 -0800 |
commit | d0ebb4154748166a4ba07baa4b424a1c45efd219 (patch) | |
tree | 5ea4d611256290f62baea1a9ffa3333b254181df /tokio/tests | |
parent | f5cb4c20422a35b51bfba3391744f8bcb54f7581 (diff) |
sync: add `Notify::notify_waiters` (#3098)
This PR makes `Notify::notify_waiters` public. The method
already exists, but it changes the way `notify_waiters`,
is used. Previously in order for the consumer to
register interest, in a notification triggered by
`notify_waiters`, the `Notified` future had to be
polled. This introduced friction when using the api
as the future had to be pinned before polled.
This change introduces a counter that tracks how many
times `notified_waiters` has been called. Upon creation of
the future the number of times is loaded. When first
polled the future compares this number with the count
state of the `Notify` type. This avoids the need for
registering the waiter upfront.
Fixes: #3066
Diffstat (limited to 'tokio/tests')
-rw-r--r-- | tokio/tests/sync_notify.rs | 34 |
1 files changed, 34 insertions, 0 deletions
diff --git a/tokio/tests/sync_notify.rs b/tokio/tests/sync_notify.rs index 8c70fe39..8ffe020f 100644 --- a/tokio/tests/sync_notify.rs +++ b/tokio/tests/sync_notify.rs @@ -100,3 +100,37 @@ fn notified_multi_notify_drop_one() { assert!(notified2.is_woken()); assert_ready!(notified2.poll()); } + +#[test] +fn notify_in_drop_after_wake() { + use futures::task::ArcWake; + use std::future::Future; + use std::sync::Arc; + + let notify = Arc::new(Notify::new()); + + struct NotifyOnDrop(Arc<Notify>); + + impl ArcWake for NotifyOnDrop { + fn wake_by_ref(_arc_self: &Arc<Self>) {} + } + + impl Drop for NotifyOnDrop { + fn drop(&mut self) { + self.0.notify_waiters(); + } + } + + let mut fut = Box::pin(async { + notify.notified().await; + }); + + { + let waker = futures::task::waker(Arc::new(NotifyOnDrop(notify.clone()))); + let mut cx = std::task::Context::from_waker(&waker); + assert!(fut.as_mut().poll(&mut cx).is_pending()); + } + + // Now, notifying **should not** deadlock + notify.notify_waiters(); +} |