Skip to content

Commit 5f053e4

Browse files
committed
Wipe Notifier FutureState when returning from a waiter.
When we return from one of the wait functions in `Notifier`, we should also ensure that the next `Future` doesn't start in the `complete` state, as we have already notified the user, as far as we're concerned. This is technically a regression from the previous commit, but as it is a logically separate change it is in its own commit.
1 parent 7527e4b commit 5f053e4

File tree

1 file changed

+21
-18
lines changed

1 file changed

+21
-18
lines changed

lightning/src/util/wakers.rs

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,20 @@ pub(crate) struct Notifier {
3333
condvar: Condvar,
3434
}
3535

36+
macro_rules! check_woken {
37+
($guard: expr, $retval: expr) => { {
38+
if $guard.0 {
39+
$guard.0 = false;
40+
if $guard.1.as_ref().map(|l| l.lock().unwrap().complete).unwrap_or(false) {
41+
// If we're about to return as woken, and the future state is marked complete, wipe
42+
// the future state and let the next future wait until we get a new notify.
43+
$guard.1.take();
44+
}
45+
return $retval;
46+
}
47+
} }
48+
}
49+
3650
impl Notifier {
3751
pub(crate) fn new() -> Self {
3852
Self {
@@ -57,16 +71,9 @@ impl Notifier {
5771
pub(crate) fn wait(&self) {
5872
loop {
5973
let mut guard = self.propagate_future_state_to_notify_flag();
60-
if guard.0 {
61-
guard.0 = false;
62-
return;
63-
}
74+
check_woken!(guard, ());
6475
guard = self.condvar.wait(guard).unwrap();
65-
let result = guard.0;
66-
if result {
67-
guard.0 = false;
68-
return
69-
}
76+
check_woken!(guard, ());
7077
}
7178
}
7279

@@ -75,24 +82,20 @@ impl Notifier {
7582
let current_time = Instant::now();
7683
loop {
7784
let mut guard = self.propagate_future_state_to_notify_flag();
78-
if guard.0 {
79-
guard.0 = false;
80-
return true;
81-
}
85+
check_woken!(guard, true);
8286
guard = self.condvar.wait_timeout(guard, max_wait).unwrap().0;
87+
check_woken!(guard, true);
8388
// Due to spurious wakeups that can happen on `wait_timeout`, here we need to check if the
8489
// desired wait time has actually passed, and if not then restart the loop with a reduced wait
8590
// time. Note that this logic can be highly simplified through the use of
8691
// `Condvar::wait_while` and `Condvar::wait_timeout_while`, if and when our MSRV is raised to
8792
// 1.42.0.
8893
let elapsed = current_time.elapsed();
89-
let result = guard.0;
90-
if result || elapsed >= max_wait {
91-
guard.0 = false;
92-
return result;
94+
if elapsed >= max_wait {
95+
return false;
9396
}
9497
match max_wait.checked_sub(elapsed) {
95-
None => return result,
98+
None => return false,
9699
Some(_) => continue
97100
}
98101
}

0 commit comments

Comments
 (0)