sync: drop wakers outside lock in semaphore (#5475)

This commit is contained in:
amab8901 2023-02-19 11:16:59 +01:00 committed by GitHub
parent a8fda87058
commit 901f6d26c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 33 additions and 1 deletions

View File

@ -444,6 +444,7 @@ impl Semaphore {
} }
assert_eq!(acquired, 0); assert_eq!(acquired, 0);
let mut old_waker = None;
// Otherwise, register the waker & enqueue the node. // Otherwise, register the waker & enqueue the node.
node.waker.with_mut(|waker| { node.waker.with_mut(|waker| {
@ -455,7 +456,7 @@ impl Semaphore {
.map(|waker| !waker.will_wake(cx.waker())) .map(|waker| !waker.will_wake(cx.waker()))
.unwrap_or(true) .unwrap_or(true)
{ {
*waker = Some(cx.waker().clone()); old_waker = std::mem::replace(waker, Some(cx.waker().clone()));
} }
}); });
@ -468,6 +469,8 @@ impl Semaphore {
waiters.queue.push_front(node); waiters.queue.push_front(node);
} }
drop(waiters);
drop(old_waker);
Pending Pending
} }

View File

@ -252,3 +252,32 @@ fn cancel_acquire_releases_permits() {
assert_eq!(6, s.available_permits()); assert_eq!(6, s.available_permits());
assert_ok!(s.try_acquire(6)); assert_ok!(s.try_acquire(6));
} }
#[test]
fn release_permits_at_drop() {
use crate::sync::semaphore::*;
use futures::task::ArcWake;
use std::future::Future;
use std::sync::Arc;
let sem = Arc::new(Semaphore::new(1));
struct ReleaseOnDrop(Option<OwnedSemaphorePermit>);
impl ArcWake for ReleaseOnDrop {
fn wake_by_ref(_arc_self: &Arc<Self>) {}
}
let mut fut = Box::pin(async {
let _permit = sem.acquire().await.unwrap();
});
// Second iteration shouldn't deadlock.
for _ in 0..=1 {
let waker = futures::task::waker(Arc::new(ReleaseOnDrop(
sem.clone().try_acquire_owned().ok(),
)));
let mut cx = std::task::Context::from_waker(&waker);
assert!(fut.as_mut().poll(&mut cx).is_pending());
}
}