tokio/runtime/time_alt/wheel/
level.rs1use super::{EntryHandle, EntryList};
2use std::ptr::NonNull;
3use std::{array, fmt};
4
5pub(crate) struct Level {
7 level: usize,
8
9 occupied: u64,
17
18 slot: [EntryList; LEVEL_MULT],
20}
21
22#[derive(Debug)]
24pub(crate) struct Expiration {
25 pub(crate) level: usize,
27
28 pub(crate) slot: usize,
30
31 pub(crate) deadline: u64,
33}
34
35const LEVEL_MULT: usize = 64;
39
40impl Level {
41 pub(crate) fn new(level: usize) -> Level {
42 Level {
43 level,
44 occupied: 0,
45 slot: array::from_fn(|_| EntryList::default()),
46 }
47 }
48
49 pub(crate) fn next_expiration(&self, now: u64) -> Option<Expiration> {
52 let slot = self.next_occupied_slot(now)?;
55
56 let level_range = level_range(self.level);
60 let slot_range = slot_range(self.level);
61
62 let level_start = now & !(level_range - 1);
65 let mut deadline = level_start + slot as u64 * slot_range;
66
67 if deadline <= now {
68 debug_assert_eq!(self.level, super::NUM_LEVELS - 1);
85
86 deadline += level_range;
87 }
88
89 debug_assert!(
90 deadline >= now,
91 "deadline={:016X}; now={:016X}; level={}; lr={:016X}, sr={:016X}, slot={}; occupied={:b}",
92 deadline,
93 now,
94 self.level,
95 level_range,
96 slot_range,
97 slot,
98 self.occupied
99 );
100
101 Some(Expiration {
102 level: self.level,
103 slot,
104 deadline,
105 })
106 }
107
108 fn next_occupied_slot(&self, now: u64) -> Option<usize> {
109 if self.occupied == 0 {
110 return None;
111 }
112
113 let now_slot = (now / slot_range(self.level)) as usize;
115 let occupied = self.occupied.rotate_right(now_slot as u32);
116 let zeros = occupied.trailing_zeros() as usize;
117 let slot = (zeros + now_slot) % LEVEL_MULT;
118
119 Some(slot)
120 }
121
122 pub(crate) unsafe fn add_entry(&mut self, hdl: EntryHandle) {
123 let deadline = hdl.deadline();
125 let slot = slot_for(deadline, self.level);
126
127 self.slot[slot].push_front(hdl);
128
129 self.occupied |= occupied_bit(slot);
130 }
131
132 pub(crate) unsafe fn remove_entry(&mut self, hdl: EntryHandle) {
133 let slot = slot_for(hdl.deadline(), self.level);
134
135 unsafe { self.slot[slot].remove(NonNull::from(&hdl)) };
136 if self.slot[slot].is_empty() {
137 debug_assert!(self.occupied & occupied_bit(slot) != 0);
139
140 self.occupied ^= occupied_bit(slot);
142 }
143 }
144
145 pub(crate) fn take_slot(&mut self, slot: usize) -> EntryList {
146 self.occupied &= !occupied_bit(slot);
147
148 std::mem::take(&mut self.slot[slot])
149 }
150}
151
152impl fmt::Debug for Level {
153 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
154 fmt.debug_struct("Level")
155 .field("occupied", &self.occupied)
156 .finish()
157 }
158}
159
160fn occupied_bit(slot: usize) -> u64 {
161 1 << slot
162}
163
164fn slot_range(level: usize) -> u64 {
165 LEVEL_MULT.pow(level as u32) as u64
166}
167
168fn level_range(level: usize) -> u64 {
169 LEVEL_MULT as u64 * slot_range(level)
170}
171
172fn slot_for(duration: u64, level: usize) -> usize {
174 ((duration >> (level * 6)) % LEVEL_MULT as u64) as usize
175}
176
177#[cfg(all(test, not(loom)))]
178mod test {
179 use super::*;
180
181 #[test]
182 fn test_slot_for() {
183 for pos in 0..64 {
184 assert_eq!(pos as usize, slot_for(pos, 0));
185 }
186
187 for level in 1..5 {
188 for pos in level..64 {
189 let a = pos * 64_usize.pow(level as u32);
190 assert_eq!(pos, slot_for(a as u64, level));
191 }
192 }
193 }
194}