@@ -58,6 +58,7 @@ use crate::loom::cell::UnsafeCell;
58
58
use crate :: loom:: sync:: atomic:: AtomicU64 ;
59
59
use crate :: loom:: sync:: atomic:: Ordering ;
60
60
61
+ use crate :: runtime:: context;
61
62
use crate :: runtime:: scheduler;
62
63
use crate :: sync:: AtomicWaker ;
63
64
use crate :: time:: Instant ;
@@ -328,6 +329,8 @@ pub(super) type EntryList = crate::util::linked_list::LinkedList<TimerShared, Ti
328
329
///
329
330
/// Note that this structure is located inside the `TimerEntry` structure.
330
331
pub ( crate ) struct TimerShared {
332
+ /// The shard id. We should never change it.
333
+ shard_id : u32 ,
331
334
/// A link within the doubly-linked list of timers on a particular level and
332
335
/// slot. Valid only if state is equal to Registered.
333
336
///
@@ -368,8 +371,9 @@ generate_addr_of_methods! {
368
371
}
369
372
370
373
impl TimerShared {
371
- pub ( super ) fn new ( ) -> Self {
374
+ pub ( super ) fn new ( shard_id : u32 ) -> Self {
372
375
Self {
376
+ shard_id,
373
377
cached_when : AtomicU64 :: new ( 0 ) ,
374
378
pointers : linked_list:: Pointers :: new ( ) ,
375
379
state : StateCell :: default ( ) ,
@@ -438,6 +442,11 @@ impl TimerShared {
438
442
pub ( super ) fn might_be_registered ( & self ) -> bool {
439
443
self . state . might_be_registered ( )
440
444
}
445
+
446
+ /// Gets the shard id.
447
+ pub ( super ) fn shard_id ( & self ) -> u32 {
448
+ self . shard_id
449
+ }
441
450
}
442
451
443
452
unsafe impl linked_list:: Link for TimerShared {
@@ -485,8 +494,10 @@ impl TimerEntry {
485
494
fn inner ( & self ) -> & TimerShared {
486
495
let inner = unsafe { & * self . inner . get ( ) } ;
487
496
if inner. is_none ( ) {
497
+ let shard_size = self . driver . driver ( ) . time ( ) . inner . get_shard_size ( ) ;
498
+ let shard_id = generate_shard_id ( shard_size) ;
488
499
unsafe {
489
- * self . inner . get ( ) = Some ( TimerShared :: new ( ) ) ;
500
+ * self . inner . get ( ) = Some ( TimerShared :: new ( shard_id ) ) ;
490
501
}
491
502
}
492
503
return inner. as_ref ( ) . unwrap ( ) ;
@@ -643,3 +654,25 @@ impl Drop for TimerEntry {
643
654
unsafe { Pin :: new_unchecked ( self ) } . as_mut ( ) . cancel ( ) ;
644
655
}
645
656
}
657
+
658
+ // Generates a shard id. If current thread is a worker thread, we use its worker index as a shard id.
659
+ // Otherwise, we use a random number generator to obtain the shard id.
660
+ cfg_rt ! {
661
+ fn generate_shard_id( shard_size: u32 ) -> u32 {
662
+ let id = context:: with_scheduler( |ctx| match ctx {
663
+ Some ( scheduler:: Context :: CurrentThread ( _ctx) ) => 0 ,
664
+ #[ cfg( feature = "rt-multi-thread" ) ]
665
+ Some ( scheduler:: Context :: MultiThread ( ctx) ) => ctx. get_worker_index( ) as u32 ,
666
+ #[ cfg( all( tokio_unstable, feature = "rt-multi-thread" ) ) ]
667
+ Some ( scheduler:: Context :: MultiThreadAlt ( ctx) ) => ctx. get_worker_index( ) as u32 ,
668
+ None => context:: thread_rng_n( shard_size) ,
669
+ } ) ;
670
+ id % shard_size
671
+ }
672
+ }
673
+
674
+ cfg_not_rt ! {
675
+ fn generate_shard_id( shard_size: u32 ) -> u32 {
676
+ context:: thread_rng_n( shard_size)
677
+ }
678
+ }
0 commit comments