@@ -280,10 +280,43 @@ pin_project! {
280
280
281
281
tokio_thread_local ! ( static CURRENT : LocalData = const { LocalData {
282
282
ctx: RcCell :: new( ) ,
283
+ wake_on_schedule: Cell :: new( false ) ,
283
284
} } ) ;
284
285
285
286
struct LocalData {
286
287
ctx : RcCell < Context > ,
288
+ wake_on_schedule : Cell < bool > ,
289
+ }
290
+
291
+ impl LocalData {
292
+ /// Should be called except when we call `LocalSet::enter`.
293
+ /// Especially when we poll a LocalSet.
294
+ #[ must_use = "dropping this guard will reset the entered state" ]
295
+ fn enter ( & self , ctx : Rc < Context > ) -> LocalDataEnterGuard < ' _ > {
296
+ let ctx = self . ctx . replace ( Some ( ctx) ) ;
297
+ let wake_on_schedule = self . wake_on_schedule . replace ( false ) ;
298
+ LocalDataEnterGuard {
299
+ local_data_ref : self ,
300
+ ctx,
301
+ wake_on_schedule,
302
+ }
303
+ }
304
+ }
305
+
306
+ /// A guard for `LocalData::enter()`
307
+ struct LocalDataEnterGuard < ' a > {
308
+ local_data_ref : & ' a LocalData ,
309
+ ctx : Option < Rc < Context > > ,
310
+ wake_on_schedule : bool ,
311
+ }
312
+
313
+ impl < ' a > Drop for LocalDataEnterGuard < ' a > {
314
+ fn drop ( & mut self ) {
315
+ self . local_data_ref . ctx . set ( self . ctx . take ( ) ) ;
316
+ self . local_data_ref
317
+ . wake_on_schedule
318
+ . set ( self . wake_on_schedule )
319
+ }
287
320
}
288
321
289
322
cfg_rt ! {
@@ -360,13 +393,26 @@ const MAX_TASKS_PER_TICK: usize = 61;
360
393
const REMOTE_FIRST_INTERVAL : u8 = 31 ;
361
394
362
395
/// Context guard for LocalSet
363
- pub struct LocalEnterGuard ( Option < Rc < Context > > ) ;
396
+ pub struct LocalEnterGuard {
397
+ ctx : Option < Rc < Context > > ,
398
+
399
+ /// Distinguishes whether the context was entered or being polled.
400
+ /// When we enter it, the value `wake_on_schedule` is set. In this case
401
+ /// `spawn_local` refers the context, whereas it is not being polled now.
402
+ wake_on_schedule : bool ,
403
+ }
364
404
365
405
impl Drop for LocalEnterGuard {
366
406
fn drop ( & mut self ) {
367
- CURRENT . with ( |LocalData { ctx, .. } | {
368
- ctx. set ( self . 0 . take ( ) ) ;
369
- } )
407
+ CURRENT . with (
408
+ |LocalData {
409
+ ctx,
410
+ wake_on_schedule,
411
+ } | {
412
+ ctx. set ( self . ctx . take ( ) ) ;
413
+ wake_on_schedule. set ( self . wake_on_schedule ) ;
414
+ } ,
415
+ )
370
416
}
371
417
}
372
418
@@ -408,10 +454,20 @@ impl LocalSet {
408
454
///
409
455
/// [`spawn_local`]: fn@crate::task::spawn_local
410
456
pub fn enter ( & self ) -> LocalEnterGuard {
411
- CURRENT . with ( |LocalData { ctx, .. } | {
412
- let old = ctx. replace ( Some ( self . context . clone ( ) ) ) ;
413
- LocalEnterGuard ( old)
414
- } )
457
+ CURRENT . with (
458
+ |LocalData {
459
+ ctx,
460
+ wake_on_schedule,
461
+ ..
462
+ } | {
463
+ let ctx = ctx. replace ( Some ( self . context . clone ( ) ) ) ;
464
+ let wake_on_schedule = wake_on_schedule. replace ( true ) ;
465
+ LocalEnterGuard {
466
+ ctx,
467
+ wake_on_schedule,
468
+ }
469
+ } ,
470
+ )
415
471
}
416
472
417
473
/// Spawns a `!Send` task onto the local task set.
@@ -667,23 +723,8 @@ impl LocalSet {
667
723
}
668
724
669
725
fn with < T > ( & self , f : impl FnOnce ( ) -> T ) -> T {
670
- CURRENT . with ( |LocalData { ctx, .. } | {
671
- struct Reset < ' a > {
672
- ctx_ref : & ' a RcCell < Context > ,
673
- val : Option < Rc < Context > > ,
674
- }
675
- impl < ' a > Drop for Reset < ' a > {
676
- fn drop ( & mut self ) {
677
- self . ctx_ref . set ( self . val . take ( ) ) ;
678
- }
679
- }
680
- let old = ctx. replace ( Some ( self . context . clone ( ) ) ) ;
681
-
682
- let _reset = Reset {
683
- ctx_ref : ctx,
684
- val : old,
685
- } ;
686
-
726
+ CURRENT . with ( |local_data| {
727
+ let _guard = local_data. enter ( self . context . clone ( ) ) ;
687
728
f ( )
688
729
} )
689
730
}
@@ -693,23 +734,8 @@ impl LocalSet {
693
734
fn with_if_possible < T > ( & self , f : impl FnOnce ( ) -> T ) -> T {
694
735
let mut f = Some ( f) ;
695
736
696
- let res = CURRENT . try_with ( |LocalData { ctx, .. } | {
697
- struct Reset < ' a > {
698
- ctx_ref : & ' a RcCell < Context > ,
699
- val : Option < Rc < Context > > ,
700
- }
701
- impl < ' a > Drop for Reset < ' a > {
702
- fn drop ( & mut self ) {
703
- self . ctx_ref . replace ( self . val . take ( ) ) ;
704
- }
705
- }
706
- let old = ctx. replace ( Some ( self . context . clone ( ) ) ) ;
707
-
708
- let _reset = Reset {
709
- ctx_ref : ctx,
710
- val : old,
711
- } ;
712
-
737
+ let res = CURRENT . try_with ( |local_data| {
738
+ let _guard = local_data. enter ( self . context . clone ( ) ) ;
713
739
( f. take ( ) . unwrap ( ) ) ( )
714
740
} ) ;
715
741
@@ -967,7 +993,10 @@ impl Shared {
967
993
fn schedule ( & self , task : task:: Notified < Arc < Self > > ) {
968
994
CURRENT . with ( |localdata| {
969
995
match localdata. ctx . get ( ) {
970
- Some ( cx) if cx. shared . ptr_eq ( self ) => unsafe {
996
+ // If the current `LocalSet` is being polled, we don't need to wake it.
997
+ // When we `enter` it, then the value `wake_on_schedule` is set to be true.
998
+ // In this case it is not being polled, so we need to wake it.
999
+ Some ( cx) if cx. shared . ptr_eq ( self ) && !localdata. wake_on_schedule . get ( ) => unsafe {
971
1000
// Safety: if the current `LocalSet` context points to this
972
1001
// `LocalSet`, then we are on the thread that owns it.
973
1002
cx. shared . local_state . task_push_back ( task) ;
0 commit comments