File tree 4 files changed +64
-5
lines changed
4 files changed +64
-5
lines changed Original file line number Diff line number Diff line change @@ -660,6 +660,10 @@ doc! {macro_rules! select {
660
660
let mut futures = & mut futures;
661
661
662
662
$crate :: macros:: support:: poll_fn( |cx| {
663
+ // Return `Pending` when the task budget is depleted since budget-aware futures
664
+ // are going to yield anyway and other futures will not cooperate.
665
+ :: std:: task:: ready!( $crate :: macros:: support:: poll_budget_available( cx) ) ;
666
+
663
667
// Track if any branch returns pending. If no branch completes
664
668
// **or** returns pending, this implies that all branches are
665
669
// disabled.
Original file line number Diff line number Diff line change @@ -7,8 +7,24 @@ cfg_macros! {
7
7
pub fn thread_rng_n( n: u32 ) -> u32 {
8
8
crate :: runtime:: context:: thread_rng_n( n)
9
9
}
10
+
11
+ cfg_coop! {
12
+ #[ doc( hidden) ]
13
+ #[ inline]
14
+ pub fn poll_budget_available( cx: & mut Context <' _>) -> Poll <( ) > {
15
+ crate :: task:: coop:: poll_budget_available( cx)
16
+ }
17
+ }
18
+
19
+ cfg_not_coop! {
20
+ #[ doc( hidden) ]
21
+ #[ inline]
22
+ pub fn poll_budget_available( _: & mut Context <' _>) -> Poll <( ) > {
23
+ Poll :: Ready ( ( ) )
24
+ }
25
+ }
10
26
}
11
27
12
28
pub use std:: future:: { Future , IntoFuture } ;
13
29
pub use std:: pin:: Pin ;
14
- pub use std:: task:: Poll ;
30
+ pub use std:: task:: { Context , Poll } ;
Original file line number Diff line number Diff line change @@ -305,12 +305,27 @@ cfg_coop! {
305
305
306
306
Poll :: Ready ( restore)
307
307
} else {
308
- defer ( cx) ;
308
+ register_waker ( cx) ;
309
309
Poll :: Pending
310
310
}
311
311
} ) . unwrap_or( Poll :: Ready ( RestoreOnPending ( Cell :: new( Budget :: unconstrained( ) ) ) ) )
312
312
}
313
313
314
+ /// Returns `Poll::Ready` if the current task has budget to consume, and `Poll::Pending` otherwise.
315
+ ///
316
+ /// Note that in contrast to `poll_proceed`, this method does not consume any budget and is used when
317
+ /// polling for budget availability.
318
+ #[ inline]
319
+ pub ( crate ) fn poll_budget_available( cx: & mut Context <' _>) -> Poll <( ) > {
320
+ if has_budget_remaining( ) {
321
+ Poll :: Ready ( ( ) )
322
+ } else {
323
+ register_waker( cx) ;
324
+
325
+ Poll :: Pending
326
+ }
327
+ }
328
+
314
329
cfg_rt! {
315
330
cfg_unstable_metrics! {
316
331
#[ inline( always) ]
@@ -326,7 +341,7 @@ cfg_coop! {
326
341
fn inc_budget_forced_yield_count( ) { }
327
342
}
328
343
329
- fn defer ( cx: & mut Context <' _>) {
344
+ fn register_waker ( cx: & mut Context <' _>) {
330
345
context:: defer( cx. waker( ) ) ;
331
346
}
332
347
}
@@ -335,8 +350,8 @@ cfg_coop! {
335
350
#[ inline( always) ]
336
351
fn inc_budget_forced_yield_count( ) { }
337
352
338
- fn defer ( cx: & mut Context <' _>) {
339
- cx. waker( ) . wake_by_ref( ) ;
353
+ fn register_waker ( cx: & mut Context <' _>) {
354
+ cx. waker( ) . wake_by_ref( )
340
355
}
341
356
}
342
357
Original file line number Diff line number Diff line change @@ -716,3 +716,27 @@ async fn temporary_lifetime_extension() {
716
716
( ) = & mut std:: future:: ready( ( ) ) => { } ,
717
717
}
718
718
}
719
+
720
+ #[ tokio:: test]
721
+ async fn select_is_budget_aware ( ) {
722
+ const BUDGET : usize = 128 ;
723
+
724
+ let task = || {
725
+ Box :: pin ( async move {
726
+ tokio:: select! {
727
+ biased;
728
+
729
+ ( ) = tokio:: task:: coop:: consume_budget( ) => { } ,
730
+ ( ) = std:: future:: ready( ( ) ) => { }
731
+ }
732
+ } )
733
+ } ;
734
+
735
+ for _ in 0 ..BUDGET {
736
+ let poll = futures:: poll!( & mut task( ) ) ;
737
+ assert ! ( poll. is_ready( ) ) ;
738
+ }
739
+
740
+ let poll = futures:: poll!( & mut task( ) ) ;
741
+ assert ! ( poll. is_pending( ) ) ;
742
+ }
You can’t perform that action at this time.
0 commit comments