@@ -152,16 +152,19 @@ impl<F: Fn() + Send> FutureCallback for F {
152
152
}
153
153
154
154
pub ( 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 > ) > ,
156
159
complete : bool ,
157
160
callbacks_made : bool ,
158
161
}
159
162
160
163
impl FutureState {
161
164
fn complete ( & mut self ) {
162
- for callback in self . callbacks . drain ( ..) {
165
+ for ( counts_as_call , callback) in self . callbacks . drain ( ..) {
163
166
callback. call ( ) ;
164
- self . callbacks_made = true ;
167
+ self . callbacks_made |= counts_as_call ;
165
168
}
166
169
self . complete = true ;
167
170
}
@@ -184,7 +187,7 @@ impl Future {
184
187
mem:: drop ( state) ;
185
188
callback. call ( ) ;
186
189
} else {
187
- state. callbacks . push ( callback) ;
190
+ state. callbacks . push ( ( true , callback) ) ;
188
191
}
189
192
}
190
193
@@ -212,10 +215,11 @@ impl<'a> StdFuture for Future {
212
215
fn poll ( self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Self :: Output > {
213
216
let mut state = self . state . lock ( ) . unwrap ( ) ;
214
217
if state. complete {
218
+ state. callbacks_made = true ;
215
219
Poll :: Ready ( ( ) )
216
220
} else {
217
221
let waker = cx. waker ( ) . clone ( ) ;
218
- state. callbacks . push ( Box :: new ( StdWaker ( waker) ) ) ;
222
+ state. callbacks . push ( ( false , Box :: new ( StdWaker ( waker) ) ) ) ;
219
223
Poll :: Pending
220
224
}
221
225
}
@@ -433,4 +437,36 @@ mod tests {
433
437
assert_eq ! ( Pin :: new( & mut future) . poll( & mut Context :: from_waker( & waker) ) , Poll :: Ready ( ( ) ) ) ;
434
438
assert_eq ! ( Pin :: new( & mut second_future) . poll( & mut Context :: from_waker( & second_waker) ) , Poll :: Ready ( ( ) ) ) ;
435
439
}
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
+ }
436
472
}
0 commit comments