1use core::sync::atomic::{AtomicU64, Ordering};
4
5use super::TaskDeadlineError;
6use crate::{thread::ThreadId, time::MonotonicDeadline};
7
8pub(super) const TASK_DEADLINE_CLASS_COUNT: usize = 4;
9static NEXT_TASK_DEADLINE_NODE_ID: AtomicU64 = AtomicU64::new(1);
10
11#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
13#[repr(transparent)]
14pub(super) struct TaskDeadlineNodeId(u64);
15
16impl TaskDeadlineNodeId {
17 const fn from_raw(raw: u64) -> Self {
18 Self(raw)
19 }
20
21 pub(super) const fn as_u64(self) -> u64 {
22 self.0
23 }
24}
25
26#[derive(Clone, Copy, Debug, Eq, PartialEq)]
28#[repr(u8)]
29pub(super) enum TaskDeadlineClass {
30 ParkSoft = 0,
31 ParkHard = 1,
32 DeadlineCbs = 2,
33 DeadlineZeroLag = 3,
34}
35
36impl TaskDeadlineClass {
37 pub(super) const ALL: [Self; TASK_DEADLINE_CLASS_COUNT] = [
38 Self::ParkSoft,
39 Self::ParkHard,
40 Self::DeadlineCbs,
41 Self::DeadlineZeroLag,
42 ];
43
44 pub(super) const fn index(self) -> usize {
45 self as usize
46 }
47}
48
49#[derive(Clone, Copy, Debug, Eq, PartialEq)]
50enum TaskDeadlineNodeKind {
51 Park,
52 DeadlineCbs,
53 DeadlineZeroLag,
54}
55
56impl TaskDeadlineNodeKind {
57 const fn supports(self, class: TaskDeadlineClass) -> bool {
58 matches!(
59 (self, class),
60 (
61 Self::Park,
62 TaskDeadlineClass::ParkSoft | TaskDeadlineClass::ParkHard
63 ) | (Self::DeadlineCbs, TaskDeadlineClass::DeadlineCbs)
64 | (Self::DeadlineZeroLag, TaskDeadlineClass::DeadlineZeroLag)
65 )
66 }
67}
68
69#[derive(Clone, Copy, Debug, Eq, PartialEq)]
71pub struct TaskDeadlineToken {
72 node: TaskDeadlineNodeId,
73 generation: u64,
74}
75
76impl TaskDeadlineToken {
77 pub const NONE: Self = Self {
79 node: TaskDeadlineNodeId::from_raw(0),
80 generation: 0,
81 };
82
83 pub const fn generation(self) -> u64 {
85 self.generation
86 }
87
88 const fn new(node: TaskDeadlineNodeId, generation: u64) -> Self {
89 Self { node, generation }
90 }
91
92 pub(super) const fn node(self) -> TaskDeadlineNodeId {
93 self.node
94 }
95}
96
97#[derive(Debug)]
99pub struct TaskDeadlineNode {
100 thread: ThreadId,
101 kind: TaskDeadlineNodeKind,
102 identity: AtomicU64,
103 sequence: AtomicU64,
104}
105
106impl TaskDeadlineNode {
107 pub const fn for_thread(thread: ThreadId) -> Self {
109 Self::new(thread, TaskDeadlineNodeKind::Park)
110 }
111
112 pub(crate) const fn deadline_cbs_for_thread(thread: ThreadId) -> Self {
113 Self::new(thread, TaskDeadlineNodeKind::DeadlineCbs)
114 }
115
116 pub(crate) const fn deadline_zero_lag_for_thread(thread: ThreadId) -> Self {
117 Self::new(thread, TaskDeadlineNodeKind::DeadlineZeroLag)
118 }
119
120 const fn new(thread: ThreadId, kind: TaskDeadlineNodeKind) -> Self {
121 Self {
122 thread,
123 kind,
124 identity: AtomicU64::new(0),
125 sequence: AtomicU64::new(0),
126 }
127 }
128
129 pub(super) const fn thread(&self) -> ThreadId {
130 self.thread
131 }
132
133 pub(super) const fn supports(&self, class: TaskDeadlineClass) -> bool {
134 self.kind.supports(class)
135 }
136
137 pub(super) fn identity(&self) -> Result<TaskDeadlineNodeId, TaskDeadlineError> {
138 let identity = self.identity.load(Ordering::Acquire);
139 if identity != 0 {
140 return Ok(TaskDeadlineNodeId::from_raw(identity));
141 }
142
143 let mut candidate = NEXT_TASK_DEADLINE_NODE_ID.load(Ordering::Relaxed);
144 loop {
145 if candidate == u64::MAX {
146 return Err(TaskDeadlineError::GenerationExhausted);
147 }
148 match NEXT_TASK_DEADLINE_NODE_ID.compare_exchange_weak(
149 candidate,
150 candidate + 1,
151 Ordering::Relaxed,
152 Ordering::Relaxed,
153 ) {
154 Ok(_) => {
155 return match self.identity.compare_exchange(
156 0,
157 candidate,
158 Ordering::Release,
159 Ordering::Acquire,
160 ) {
161 Ok(_) => Ok(TaskDeadlineNodeId::from_raw(candidate)),
162 Err(published) => Ok(TaskDeadlineNodeId::from_raw(published)),
163 };
164 }
165 Err(updated) => candidate = updated,
166 }
167 }
168 }
169
170 pub(super) fn next_token(
171 &self,
172 identity: TaskDeadlineNodeId,
173 ) -> Result<TaskDeadlineToken, TaskDeadlineError> {
174 debug_assert_eq!(self.identity.load(Ordering::Relaxed), identity.as_u64());
175 let mut sequence = self.sequence.load(Ordering::Relaxed);
176 loop {
177 if sequence == u64::MAX {
178 return Err(TaskDeadlineError::GenerationExhausted);
179 }
180 match self.sequence.compare_exchange_weak(
181 sequence,
182 sequence + 1,
183 Ordering::Relaxed,
184 Ordering::Relaxed,
185 ) {
186 Ok(_) => return Ok(TaskDeadlineToken::new(identity, sequence + 1)),
187 Err(updated) => sequence = updated,
188 }
189 }
190 }
191}
192
193#[non_exhaustive]
198#[derive(Clone, Copy, Debug, Eq, PartialEq)]
199pub enum TaskDeadlineKind {
200 ParkTimeout { park_generation: u64 },
202 DeadlineCbs,
204 DeadlineZeroLag,
206}
207
208impl TaskDeadlineKind {
209 pub const fn park_timeout(park_generation: u64) -> Self {
211 Self::ParkTimeout { park_generation }
212 }
213
214 pub const fn park_generation(self) -> Option<u64> {
216 match self {
217 Self::ParkTimeout { park_generation } => Some(park_generation),
218 Self::DeadlineCbs | Self::DeadlineZeroLag => None,
219 }
220 }
221
222 pub(super) const fn default_class(self) -> TaskDeadlineClass {
223 match self {
224 Self::ParkTimeout { .. } => TaskDeadlineClass::ParkSoft,
225 Self::DeadlineCbs => TaskDeadlineClass::DeadlineCbs,
226 Self::DeadlineZeroLag => TaskDeadlineClass::DeadlineZeroLag,
227 }
228 }
229}
230
231#[must_use = "a task-deadline registration must remain owned until cancellation or expiration"]
237#[derive(Debug, Eq, PartialEq)]
238pub struct TaskDeadlineRegistration {
239 thread: ThreadId,
240 token: TaskDeadlineToken,
241 deadline: MonotonicDeadline,
242 kind: TaskDeadlineKind,
243 class: TaskDeadlineClass,
244}
245
246impl TaskDeadlineRegistration {
247 pub(super) const fn new(
248 thread: ThreadId,
249 token: TaskDeadlineToken,
250 deadline: MonotonicDeadline,
251 kind: TaskDeadlineKind,
252 class: TaskDeadlineClass,
253 ) -> Self {
254 Self {
255 thread,
256 token,
257 deadline,
258 kind,
259 class,
260 }
261 }
262
263 pub const fn thread(&self) -> ThreadId {
265 self.thread
266 }
267
268 pub const fn token(&self) -> TaskDeadlineToken {
270 self.token
271 }
272
273 pub const fn deadline(&self) -> MonotonicDeadline {
275 self.deadline
276 }
277
278 pub const fn kind(&self) -> TaskDeadlineKind {
280 self.kind
281 }
282
283 pub(crate) const fn may_enter_soft_expiry_buffer(&self) -> bool {
286 matches!(self.class, TaskDeadlineClass::ParkSoft)
287 }
288
289 pub(super) const fn class(&self) -> TaskDeadlineClass {
290 self.class
291 }
292}
293
294#[derive(Clone, Copy, Debug, Eq, PartialEq)]
296pub struct ExpiredTaskDeadline {
297 thread: ThreadId,
298 token: TaskDeadlineToken,
299 deadline: MonotonicDeadline,
300 valid: bool,
301 kind: TaskDeadlineKind,
302}
303
304impl ExpiredTaskDeadline {
305 pub const EMPTY: Self = Self {
307 thread: ThreadId::from_parts(0, 0),
308 token: TaskDeadlineToken::NONE,
309 deadline: MonotonicDeadline::ORIGIN,
310 valid: false,
311 kind: TaskDeadlineKind::ParkTimeout { park_generation: 0 },
312 };
313
314 pub(super) const fn new(
315 thread: ThreadId,
316 token: TaskDeadlineToken,
317 deadline: MonotonicDeadline,
318 kind: TaskDeadlineKind,
319 ) -> Self {
320 Self {
321 thread,
322 token,
323 deadline,
324 valid: true,
325 kind,
326 }
327 }
328
329 pub const fn thread(self) -> Option<ThreadId> {
331 if self.valid { Some(self.thread) } else { None }
332 }
333
334 pub const fn token(self) -> TaskDeadlineToken {
336 self.token
337 }
338
339 pub const fn deadline(self) -> Option<MonotonicDeadline> {
341 if self.valid {
342 Some(self.deadline)
343 } else {
344 None
345 }
346 }
347
348 pub const fn kind(self) -> Option<TaskDeadlineKind> {
350 if self.valid { Some(self.kind) } else { None }
351 }
352
353 pub const fn is_valid(self) -> bool {
355 self.valid
356 }
357}