Skip to content

Commit 856b418

Browse files
authored
fix: poison-proof Cancel's waker lock (#59)
1 parent 0bbeb0a commit 856b418

1 file changed

Lines changed: 10 additions & 2 deletions

File tree

crates/eye_declare/src/task.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,17 @@ impl Cancel {
6262
}
6363
}
6464

65+
// Poison-proof, like PersistState: cancel() runs from Task::drop,
66+
// including on unwind paths, where a poisoned mutex would escalate
67+
// into a double panic — and a stored waker is valid regardless of
68+
// who panicked.
69+
fn waker(&self) -> std::sync::MutexGuard<'_, Option<Waker>> {
70+
self.waker.lock().unwrap_or_else(PoisonError::into_inner)
71+
}
72+
6573
pub(crate) fn cancel(&self) {
6674
self.cancelled.store(true, Ordering::SeqCst);
67-
if let Some(waker) = self.waker.lock().unwrap().take() {
75+
if let Some(waker) = self.waker().take() {
6876
waker.wake();
6977
}
7078
}
@@ -94,7 +102,7 @@ impl Future for Cancelled {
94102
if self.cancel.is_cancelled() {
95103
return Poll::Ready(());
96104
}
97-
*self.cancel.waker.lock().unwrap() = Some(cx.waker().clone());
105+
*self.cancel.waker() = Some(cx.waker().clone());
98106
// Re-check after storing the waker to close the race with a
99107
// concurrent cancel() that ran between the check and the store.
100108
if self.cancel.is_cancelled() {

0 commit comments

Comments
 (0)