Skip to content

Commit 5f404b9

Browse files
committed
Give Futures for a FutureState an idx and track StdWaker idxn
When an `std::future::Future` is `poll()`ed, we're only supposed to use the latest `Waker` provided. However, we currently push an `StdWaker` onto our callback list every time `poll` is called, waking every `Waker` but also using more and more memory until the `Future` itself is woken. Here we take a step towards fixing this by giving each `Future` a unique index and storing which `Future` an `StdWaker` came from in the callback list. This sets us up to deduplicate `StdWaker`s by `Future`s in the next commit.
1 parent 2c98720 commit 5f404b9

File tree

1 file changed

+26
-13
lines changed

1 file changed

+26
-13
lines changed

lightning/src/util/wakers.rs

+26-13
Original file line numberDiff line numberDiff line change
@@ -56,26 +56,33 @@ impl Notifier {
5656
/// Gets a [`Future`] that will get woken up with any waiters
5757
pub(crate) fn get_future(&self) -> Future {
5858
let mut lock = self.notify_pending.lock().unwrap();
59+
let mut self_idx = 0;
5960
if let Some(existing_state) = &lock.1 {
60-
if existing_state.lock().unwrap().callbacks_made {
61+
let mut locked = existing_state.lock().unwrap();
62+
if locked.callbacks_made {
6163
// If the existing `FutureState` has completed and actually made callbacks,
6264
// consider the notification flag to have been cleared and reset the future state.
65+
mem::drop(locked);
6366
lock.1.take();
6467
lock.0 = false;
68+
} else {
69+
self_idx = locked.next_idx;
70+
locked.next_idx += 1;
6571
}
6672
}
6773
if let Some(existing_state) = &lock.1 {
68-
Future { state: Arc::clone(&existing_state) }
74+
Future { state: Arc::clone(&existing_state), self_idx }
6975
} else {
7076
let state = Arc::new(Mutex::new(FutureState {
7177
callbacks: Vec::new(),
7278
std_future_callbacks: Vec::new(),
7379
callbacks_with_state: Vec::new(),
7480
complete: lock.0,
7581
callbacks_made: false,
82+
next_idx: 1,
7683
}));
7784
lock.1 = Some(Arc::clone(&state));
78-
Future { state }
85+
Future { state, self_idx: 0 }
7986
}
8087
}
8188

@@ -115,10 +122,11 @@ pub(crate) struct FutureState {
115122
// we only count it after another `poll()` and the second wakes a `Sleeper` which handles
116123
// setting `callbacks_made` itself).
117124
callbacks: Vec<Box<dyn FutureCallback>>,
118-
std_future_callbacks: Vec<StdWaker>,
125+
std_future_callbacks: Vec<(usize, StdWaker)>,
119126
callbacks_with_state: Vec<Box<dyn Fn(&Arc<Mutex<FutureState>>) -> () + Send>>,
120127
complete: bool,
121128
callbacks_made: bool,
129+
next_idx: usize,
122130
}
123131

124132
fn complete_future(this: &Arc<Mutex<FutureState>>) -> bool {
@@ -128,7 +136,7 @@ fn complete_future(this: &Arc<Mutex<FutureState>>) -> bool {
128136
callback.call();
129137
state.callbacks_made = true;
130138
}
131-
for waker in state.std_future_callbacks.drain(..) {
139+
for (_, waker) in state.std_future_callbacks.drain(..) {
132140
waker.0.wake_by_ref();
133141
}
134142
for callback in state.callbacks_with_state.drain(..) {
@@ -139,11 +147,9 @@ fn complete_future(this: &Arc<Mutex<FutureState>>) -> bool {
139147
}
140148

141149
/// A simple future which can complete once, and calls some callback(s) when it does so.
142-
///
143-
/// Clones can be made and all futures cloned from the same source will complete at the same time.
144-
#[derive(Clone)]
145150
pub struct Future {
146151
state: Arc<Mutex<FutureState>>,
152+
self_idx: usize,
147153
}
148154

149155
impl Future {
@@ -210,7 +216,7 @@ impl<'a> StdFuture for Future {
210216
Poll::Ready(())
211217
} else {
212218
let waker = cx.waker().clone();
213-
state.std_future_callbacks.push(StdWaker(waker));
219+
state.std_future_callbacks.push((self.self_idx, StdWaker(waker)));
214220
Poll::Pending
215221
}
216222
}
@@ -461,7 +467,9 @@ mod tests {
461467
callbacks_with_state: Vec::new(),
462468
complete: false,
463469
callbacks_made: false,
464-
}))
470+
next_idx: 1,
471+
})),
472+
self_idx: 0,
465473
};
466474
let callback = Arc::new(AtomicBool::new(false));
467475
let callback_ref = Arc::clone(&callback);
@@ -478,10 +486,13 @@ mod tests {
478486
let future = Future {
479487
state: Arc::new(Mutex::new(FutureState {
480488
callbacks: Vec::new(),
489+
std_future_callbacks: Vec::new(),
481490
callbacks_with_state: Vec::new(),
482491
complete: false,
483492
callbacks_made: false,
484-
}))
493+
next_idx: 1,
494+
})),
495+
self_idx: 0,
485496
};
486497
complete_future(&future.state);
487498

@@ -521,9 +532,11 @@ mod tests {
521532
callbacks_with_state: Vec::new(),
522533
complete: false,
523534
callbacks_made: false,
524-
}))
535+
next_idx: 2,
536+
})),
537+
self_idx: 0,
525538
};
526-
let mut second_future = Future { state: Arc::clone(&future.state) };
539+
let mut second_future = Future { state: Arc::clone(&future.state), self_idx: 1 };
527540

528541
let (woken, waker) = create_waker();
529542
assert_eq!(Pin::new(&mut future).poll(&mut Context::from_waker(&waker)), Poll::Pending);

0 commit comments

Comments
 (0)