@@ -152,16 +152,19 @@ impl<F: Fn() + Send> FutureCallback for F {
152152}
153153
154154pub ( crate ) struct FutureState {
155- callbacks : Vec < Box < dyn FutureCallback > > ,
155+ // When we're tracking whether a callback counts as having woken the user's code, we check the
156+ // first bool - set to false if we're just calling a Waker, and true if we're calling an actual
157+ // user-provided function.
158+ callbacks : Vec < ( bool , Box < dyn FutureCallback > ) > ,
156159 complete : bool ,
157160 callbacks_made : bool ,
158161}
159162
160163impl FutureState {
161164 fn complete ( & mut self ) {
162- for callback in self . callbacks . drain ( ..) {
165+ for ( counts_as_call , callback) in self . callbacks . drain ( ..) {
163166 callback. call ( ) ;
164- self . callbacks_made = true ;
167+ self . callbacks_made |= counts_as_call ;
165168 }
166169 self . complete = true ;
167170 }
@@ -184,7 +187,7 @@ impl Future {
184187 mem:: drop ( state) ;
185188 callback. call ( ) ;
186189 } else {
187- state. callbacks . push ( callback) ;
190+ state. callbacks . push ( ( true , callback) ) ;
188191 }
189192 }
190193
@@ -212,10 +215,11 @@ impl<'a> StdFuture for Future {
212215 fn poll ( self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Self :: Output > {
213216 let mut state = self . state . lock ( ) . unwrap ( ) ;
214217 if state. complete {
218+ state. callbacks_made = true ;
215219 Poll :: Ready ( ( ) )
216220 } else {
217221 let waker = cx. waker ( ) . clone ( ) ;
218- state. callbacks . push ( Box :: new ( StdWaker ( waker) ) ) ;
222+ state. callbacks . push ( ( false , Box :: new ( StdWaker ( waker) ) ) ) ;
219223 Poll :: Pending
220224 }
221225 }
@@ -433,4 +437,36 @@ mod tests {
433437 assert_eq ! ( Pin :: new( & mut future) . poll( & mut Context :: from_waker( & waker) ) , Poll :: Ready ( ( ) ) ) ;
434438 assert_eq ! ( Pin :: new( & mut second_future) . poll( & mut Context :: from_waker( & second_waker) ) , Poll :: Ready ( ( ) ) ) ;
435439 }
440+
441+ #[ test]
442+ fn test_dropped_future_doesnt_count ( ) {
443+ // Tests that if a Future gets drop'd before it is poll()ed `Ready` it doesn't count as
444+ // having been woken, leaving the notify-required flag set.
445+ let notifier = Notifier :: new ( ) ;
446+ notifier. notify ( ) ;
447+
448+ // If we get a future and don't touch it we're definitely still notify-required.
449+ notifier. get_future ( ) ;
450+ assert ! ( notifier. wait_timeout( Duration :: from_millis( 1 ) ) ) ;
451+ assert ! ( !notifier. wait_timeout( Duration :: from_millis( 1 ) ) ) ;
452+
453+ // Even if we poll'd once but didn't observe a `Ready`, we should be notify-required.
454+ let mut future = notifier. get_future ( ) ;
455+ let ( woken, waker) = create_waker ( ) ;
456+ assert_eq ! ( Pin :: new( & mut future) . poll( & mut Context :: from_waker( & waker) ) , Poll :: Pending ) ;
457+
458+ notifier. notify ( ) ;
459+ assert ! ( woken. load( Ordering :: SeqCst ) ) ;
460+ assert ! ( notifier. wait_timeout( Duration :: from_millis( 1 ) ) ) ;
461+
462+ // However, once we do poll `Ready` it should wipe the notify-required flag.
463+ let mut future = notifier. get_future ( ) ;
464+ let ( woken, waker) = create_waker ( ) ;
465+ assert_eq ! ( Pin :: new( & mut future) . poll( & mut Context :: from_waker( & waker) ) , Poll :: Pending ) ;
466+
467+ notifier. notify ( ) ;
468+ assert ! ( woken. load( Ordering :: SeqCst ) ) ;
469+ assert_eq ! ( Pin :: new( & mut future) . poll( & mut Context :: from_waker( & waker) ) , Poll :: Ready ( ( ) ) ) ;
470+ assert ! ( !notifier. wait_timeout( Duration :: from_millis( 1 ) ) ) ;
471+ }
436472}
0 commit comments