X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Futil%2Fwakers.rs;h=e55ba37ffd84c99ba19ddc625a5cfa7e9f23ed56;hb=90c976394c3bb5726dbb6950256afcbc33ddf4a7;hp=9636466aaa2f1d750cb14b3c630aa56e4c764e2f;hpb=c6890cfc3317c0b1ba4d1e6cd71b3bb75386571e;p=rust-lightning diff --git a/lightning/src/util/wakers.rs b/lightning/src/util/wakers.rs index 9636466a..e55ba37f 100644 --- a/lightning/src/util/wakers.rs +++ b/lightning/src/util/wakers.rs @@ -15,17 +15,17 @@ use alloc::sync::Arc; use core::mem; -use core::time::Duration; use sync::{Condvar, Mutex}; +use prelude::*; + #[cfg(any(test, feature = "std"))] -use std::time::Instant; +use std::time::{Duration, Instant}; use core::future::Future as StdFuture; use core::task::{Context, Poll}; use core::pin::Pin; -use prelude::*; /// Used to signal to one of many waiters that the condition they're waiting on has happened. pub(crate) struct Notifier { @@ -103,7 +103,7 @@ impl Notifier { Future { state: Arc::new(Mutex::new(FutureState { callbacks: Vec::new(), - complete: false, + complete: true, })) } } else if let Some(existing_state) = &lock.1 { @@ -163,6 +163,8 @@ pub struct Future { impl Future { /// Registers a callback to be called upon completion of this future. If the future has already /// completed, the callback will be called immediately. + /// + /// (C-not exported) use the bindings-only `register_callback_fn` instead pub fn register_callback(&self, callback: Box) { let mut state = self.state.lock().unwrap(); if state.complete { @@ -172,6 +174,16 @@ impl Future { state.callbacks.push(callback); } } + + // C bindings don't (currently) know how to map `Box`, and while it could add the + // following wrapper, doing it in the bindings is currently much more work than simply doing it + // here. + /// Registers a callback to be called upon completion of this future. If the future has already + /// completed, the callback will be called immediately. + #[cfg(c_bindings)] + pub fn register_callback_fn(&self, callback: F) { + self.register_callback(Box::new(callback)); + } } mod std_future { @@ -205,6 +217,20 @@ mod tests { use core::future::Future as FutureTrait; use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker}; + #[test] + fn notifier_pre_notified_future() { + // Previously, if we generated a future after a `Notifier` had been notified, the future + // would never complete. This tests this behavior, ensuring the future instead completes + // immediately. + let notifier = Notifier::new(); + notifier.notify(); + + let callback = Arc::new(AtomicBool::new(false)); + let callback_ref = Arc::clone(&callback); + notifier.get_future().register_callback(Box::new(move || assert!(!callback_ref.fetch_or(true, Ordering::SeqCst)))); + assert!(callback.load(Ordering::SeqCst)); + } + #[cfg(feature = "std")] #[test] fn test_wait_timeout() { @@ -292,7 +318,7 @@ mod tests { // waker, which we do here with a trivial Arc data element to track woke-ness. const WAKER_V_TABLE: RawWakerVTable = RawWakerVTable::new(waker_clone, wake, wake_by_ref, drop); unsafe fn wake_by_ref(ptr: *const ()) { let p = ptr as *const Arc; assert!(!(*p).fetch_or(true, Ordering::SeqCst)); } - unsafe fn drop(ptr: *const ()) { let p = ptr as *mut Arc; Box::from_raw(p); } + unsafe fn drop(ptr: *const ()) { let p = ptr as *mut Arc; let _freed = Box::from_raw(p); } unsafe fn wake(ptr: *const ()) { wake_by_ref(ptr); drop(ptr); } unsafe fn waker_clone(ptr: *const ()) -> RawWaker { let p = ptr as *const Arc;