1use alloc::{boxed::Box, vec::Vec};
4use core::{
5 fmt,
6 num::NonZeroU64,
7 sync::atomic::{AtomicU64, Ordering},
8 time::Duration,
9};
10
11static NEXT_KERNEL_TIMER_ID: AtomicU64 = AtomicU64::new(1);
12
13#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
15pub struct TimerCpuId(usize);
16
17impl TimerCpuId {
18 pub const fn new(cpu_id: usize) -> Self {
19 Self(cpu_id)
20 }
21
22 pub const fn as_usize(self) -> usize {
23 self.0
24 }
25}
26
27#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
29pub struct MonotonicDeadline(Duration);
30
31impl MonotonicDeadline {
32 pub fn from_duration(deadline: Duration) -> Result<Self, KernelTimerError> {
33 let nanos = deadline.as_nanos();
34 if nanos >= u128::from(u64::MAX) {
35 return Err(KernelTimerError::InvalidDeadline);
36 }
37 Ok(Self(deadline))
38 }
39
40 pub fn from_nanos(nanos: u64) -> Result<Self, KernelTimerError> {
41 Self::from_duration(Duration::from_nanos(nanos))
42 }
43
44 pub const fn as_duration(self) -> Duration {
45 self.0
46 }
47}
48
49#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
51pub struct MonotonicInstant(Duration);
52
53impl MonotonicInstant {
54 pub fn from_duration(now: Duration) -> Result<Self, KernelTimerError> {
55 let nanos = now.as_nanos();
56 if nanos >= u128::from(u64::MAX) {
57 return Err(KernelTimerError::InvalidDeadline);
58 }
59 Ok(Self(now))
60 }
61
62 pub fn from_nanos(nanos: u64) -> Result<Self, KernelTimerError> {
63 Self::from_duration(Duration::from_nanos(nanos))
64 }
65
66 pub const fn as_duration(self) -> Duration {
67 self.0
68 }
69
70 pub fn reached(self, deadline: MonotonicDeadline) -> bool {
71 self.0 >= deadline.0
72 }
73}
74
75#[derive(Clone, Copy, Debug, Eq, PartialEq, thiserror::Error)]
77pub enum KernelTimerError {
78 #[error("kernel timer registration and cancellation are unavailable in hard IRQ context")]
79 UnsafeContext,
80 #[error("timer deadline must be finite")]
81 InvalidDeadline,
82 #[error("kernel timer identity space is exhausted")]
83 GenerationExhausted,
84 #[error("CPU {cpu_id} has no initialized timer base")]
85 CpuUnavailable { cpu_id: usize },
86 #[error("kernel timer capacity is exhausted on CPU {cpu_id}")]
87 Capacity { cpu_id: usize },
88 #[error("kernel timer handle is stale")]
89 StaleHandle,
90 #[error("kernel timer owner mismatch: expected CPU {expected}, current CPU {actual}")]
91 OwnerMismatch { expected: usize, actual: usize },
92}
93
94pub type KernelTimerCallback = Box<dyn FnOnce(MonotonicInstant) + Send + 'static>;
96
97pub type RestartableKernelTimerCallback =
99 Box<dyn FnMut(MonotonicInstant) -> KernelTimerAction + Send + 'static>;
100pub type HardRestartableKernelTimerCallback =
102 Box<dyn FnMut(MonotonicInstant) -> HardKernelTimerAction + Send + 'static>;
103
104pub struct HardKernelTimerCallback {
111 callback: HardRestartableKernelTimerCallback,
112}
113
114impl HardKernelTimerCallback {
115 pub unsafe fn new(callback: HardRestartableKernelTimerCallback) -> Self {
124 Self { callback }
125 }
126
127 fn invoke(&mut self, expired_at: MonotonicInstant) -> HardKernelTimerAction {
128 (self.callback)(expired_at)
129 }
130}
131
132#[derive(Clone, Copy, Debug, Eq, PartialEq)]
134pub enum HardKernelTimerAction {
135 Complete,
137 Disarm,
139 Rearm(MonotonicDeadline),
141}
142
143#[derive(Clone, Copy, Debug, Eq, PartialEq)]
145pub enum KernelTimerAction {
146 Complete,
148 Rearm(MonotonicDeadline),
150}
151
152#[derive(Clone, Copy, Debug, Eq, PartialEq)]
154pub struct KernelTimerHandle {
155 owner: TimerCpuId,
156 identity: NonZeroU64,
157}
158
159impl KernelTimerHandle {
160 pub(crate) const fn new(owner: TimerCpuId, identity: NonZeroU64) -> Self {
161 Self { owner, identity }
162 }
163
164 pub const fn owner(self) -> TimerCpuId {
166 self.owner
167 }
168
169 pub(crate) const fn identity(self) -> NonZeroU64 {
170 self.identity
171 }
172}
173
174#[derive(Clone, Copy, Debug, Eq, PartialEq)]
176pub enum KernelTimerCancelOutcome {
177 Cancelled,
179 NotCancelled,
181}
182
183pub(crate) enum KernelTimerQueueCancel {
184 Cancelled(KernelTimerEntry),
185 Executing,
186 Stale,
187}
188
189pub(crate) struct KernelTimerEntry {
190 identity: NonZeroU64,
191 deadline: Option<MonotonicDeadline>,
192 expired_at: Option<MonotonicInstant>,
193 callback: KernelTimerCallbackState,
194}
195
196enum KernelTimerCallbackState {
197 OneShot(Option<KernelTimerCallback>),
198 Restartable(RestartableKernelTimerCallback),
199 HardRestartable(HardKernelTimerCallback),
200}
201
202impl KernelTimerEntry {
203 pub(crate) fn new(
204 deadline: MonotonicDeadline,
205 callback: KernelTimerCallback,
206 ) -> Result<Self, KernelTimerError> {
207 Ok(Self {
208 identity: next_kernel_timer_identity()?,
209 deadline: Some(deadline),
210 expired_at: None,
211 callback: KernelTimerCallbackState::OneShot(Some(callback)),
212 })
213 }
214
215 pub(crate) fn new_restartable(
216 deadline: MonotonicDeadline,
217 callback: RestartableKernelTimerCallback,
218 ) -> Result<Self, KernelTimerError> {
219 Ok(Self {
220 identity: next_kernel_timer_identity()?,
221 deadline: Some(deadline),
222 expired_at: None,
223 callback: KernelTimerCallbackState::Restartable(callback),
224 })
225 }
226
227 pub(crate) fn new_hard_restartable(
228 deadline: MonotonicDeadline,
229 callback: HardKernelTimerCallback,
230 ) -> Result<Self, KernelTimerError> {
231 Ok(Self {
232 identity: next_kernel_timer_identity()?,
233 deadline: Some(deadline),
234 expired_at: None,
235 callback: KernelTimerCallbackState::HardRestartable(callback),
236 })
237 }
238
239 fn deadline(&self) -> MonotonicDeadline {
240 self.deadline
241 .expect("only an armed kernel timer has a deadline")
242 }
243
244 pub(crate) const fn deadline_for_registration(&self) -> Option<MonotonicDeadline> {
245 self.deadline
246 }
247
248 const fn identity(&self) -> NonZeroU64 {
249 self.identity
250 }
251
252 fn expire(&mut self, now: MonotonicInstant) {
253 assert!(self.expired_at.replace(now).is_none());
254 }
255
256 fn rearm(&mut self, deadline: MonotonicDeadline) {
257 self.deadline = Some(deadline);
258 self.expired_at = None;
259 }
260
261 fn disarm(&mut self) -> MonotonicDeadline {
262 self.expired_at = None;
263 self.deadline
264 .take()
265 .expect("only an armed kernel timer can be disarmed")
266 }
267
268 const fn is_armed(&self) -> bool {
269 self.deadline.is_some()
270 }
271
272 const fn is_hard(&self) -> bool {
273 matches!(self.callback, KernelTimerCallbackState::HardRestartable(_))
274 }
275}
276
277fn next_kernel_timer_identity() -> Result<NonZeroU64, KernelTimerError> {
278 let identity = NEXT_KERNEL_TIMER_ID
279 .try_update(Ordering::Relaxed, Ordering::Relaxed, |current| {
280 current.checked_add(1)
281 })
282 .map_err(|_| KernelTimerError::GenerationExhausted)?;
283 NonZeroU64::new(identity).ok_or(KernelTimerError::GenerationExhausted)
284}
285
286impl fmt::Debug for KernelTimerEntry {
287 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
288 formatter
289 .debug_struct("KernelTimerEntry")
290 .field("identity", &self.identity)
291 .field("deadline", &self.deadline)
292 .field("expired_at", &self.expired_at)
293 .finish_non_exhaustive()
294 }
295}
296
297pub(crate) struct KernelTimerExecution {
302 entry: KernelTimerEntry,
303}
304
305impl KernelTimerExecution {
306 pub(crate) fn invoke_soft(&mut self) -> KernelTimerAction {
307 let expired_at = self
308 .entry
309 .expired_at
310 .expect("claimed kernel timer must have an expiry sample");
311 match &mut self.entry.callback {
312 KernelTimerCallbackState::OneShot(callback) => {
313 callback
314 .take()
315 .expect("kernel timer callback may execute only once")(
316 expired_at
317 );
318 KernelTimerAction::Complete
319 }
320 KernelTimerCallbackState::Restartable(callback) => callback(expired_at),
321 KernelTimerCallbackState::HardRestartable(_) => {
322 panic!("hard kernel timer must not execute in ktimers/%u")
323 }
324 }
325 }
326
327 pub(crate) unsafe fn invoke_hard(&mut self) -> HardKernelTimerAction {
334 let expired_at = self
335 .entry
336 .expired_at
337 .expect("claimed hard kernel timer must have an expiry sample");
338 match &mut self.entry.callback {
339 KernelTimerCallbackState::HardRestartable(callback) => callback.invoke(expired_at),
340 KernelTimerCallbackState::OneShot(_) | KernelTimerCallbackState::Restartable(_) => {
341 panic!("task-context kernel timer must not execute in hard IRQ")
342 }
343 }
344 }
345
346 const fn is_hard(&self) -> bool {
347 self.entry.is_hard()
348 }
349}
350
351#[derive(Clone, Copy, Debug, Eq, PartialEq)]
352struct ExecutingKernelTimer {
353 identity: NonZeroU64,
354 disposition: ExecutingKernelTimerDisposition,
355}
356
357#[derive(Clone, Copy, Debug, Eq, PartialEq)]
358enum ExecutingKernelTimerDisposition {
359 Continue,
360 Disarm,
361 Rearm(MonotonicDeadline),
362 Destroy,
363}
364
365#[derive(Clone, Copy, Debug, Eq, PartialEq)]
367pub(crate) struct KernelTimerExpireBatch {
368 expired: usize,
369 pending: bool,
370}
371
372impl KernelTimerExpireBatch {
373 pub(crate) const fn expired(self) -> usize {
374 self.expired
375 }
376
377 pub(crate) const fn pending(self) -> bool {
378 self.pending
379 }
380}
381
382pub(crate) struct KernelTimerQueue {
388 active: Vec<KernelTimerEntry>,
389 inactive: Vec<KernelTimerEntry>,
390 expired: Vec<KernelTimerEntry>,
391 executing: Vec<ExecutingKernelTimer>,
392 completed: Vec<KernelTimerEntry>,
393 capacity: usize,
394}
395
396impl KernelTimerQueue {
397 pub(crate) const fn new(capacity: usize) -> Self {
398 Self {
399 active: Vec::new(),
400 inactive: Vec::new(),
401 expired: Vec::new(),
402 executing: Vec::new(),
403 completed: Vec::new(),
404 capacity,
405 }
406 }
407
408 pub(crate) fn reserve_transition_capacity(
410 &mut self,
411 cpu_id: usize,
412 ) -> Result<(), KernelTimerError> {
413 self.active
414 .try_reserve_exact(self.capacity)
415 .map_err(|_| KernelTimerError::Capacity { cpu_id })?;
416 self.inactive
417 .try_reserve_exact(self.capacity)
418 .map_err(|_| KernelTimerError::Capacity { cpu_id })?;
419 self.expired
420 .try_reserve_exact(self.capacity)
421 .map_err(|_| KernelTimerError::Capacity { cpu_id })?;
422 self.executing
423 .try_reserve_exact(self.capacity)
424 .map_err(|_| KernelTimerError::Capacity { cpu_id })?;
425 self.completed
426 .try_reserve_exact(self.capacity)
427 .map_err(|_| KernelTimerError::Capacity { cpu_id })?;
428 Ok(())
429 }
430
431 pub(crate) fn insert(
432 &mut self,
433 owner: TimerCpuId,
434 entry: KernelTimerEntry,
435 ) -> Result<KernelTimerHandle, KernelTimerEntry> {
436 if self.active.len()
437 + self.inactive.len()
438 + self.expired.len()
439 + self.executing.len()
440 + self.completed.len()
441 >= self.capacity
442 {
443 return Err(entry);
444 }
445 let handle = KernelTimerHandle::new(owner, entry.identity());
446 self.insert_entry(entry);
447 Ok(handle)
448 }
449
450 pub(crate) fn cancel(&mut self, handle: KernelTimerHandle) -> KernelTimerQueueCancel {
451 if let Some(index) = self
452 .active
453 .iter()
454 .position(|entry| entry.identity() == handle.identity())
455 {
456 return KernelTimerQueueCancel::Cancelled(self.active.remove(index));
457 }
458 if let Some(index) = self
459 .inactive
460 .iter()
461 .position(|entry| entry.identity() == handle.identity())
462 {
463 return KernelTimerQueueCancel::Cancelled(self.inactive.remove(index));
464 }
465 let removed = self
466 .expired
467 .iter()
468 .position(|entry| entry.identity() == handle.identity())
469 .map(|index| self.expired.remove(index));
470 if let Some(entry) = removed {
471 return KernelTimerQueueCancel::Cancelled(entry);
472 }
473 if let Some(executing) = self
474 .executing
475 .iter_mut()
476 .find(|entry| entry.identity == handle.identity())
477 {
478 executing.disposition = ExecutingKernelTimerDisposition::Destroy;
479 return KernelTimerQueueCancel::Executing;
480 }
481 KernelTimerQueueCancel::Stale
482 }
483
484 pub(crate) fn arm_hard(
485 &mut self,
486 handle: KernelTimerHandle,
487 deadline: MonotonicDeadline,
488 ) -> bool {
489 if let Some(index) = self
490 .inactive
491 .iter()
492 .position(|entry| entry.identity() == handle.identity() && entry.is_hard())
493 {
494 let mut entry = self.inactive.remove(index);
495 entry.rearm(deadline);
496 self.insert_at(entry);
497 return true;
498 }
499 if let Some(executing) = self
500 .executing
501 .iter_mut()
502 .find(|entry| entry.identity == handle.identity())
503 && executing.disposition != ExecutingKernelTimerDisposition::Destroy
504 {
505 executing.disposition = ExecutingKernelTimerDisposition::Rearm(deadline);
509 return true;
510 }
511 false
512 }
513
514 pub(crate) fn disarm_hard(
520 &mut self,
521 handle: KernelTimerHandle,
522 ) -> Option<Option<MonotonicDeadline>> {
523 if self
524 .inactive
525 .iter()
526 .any(|entry| entry.identity() == handle.identity() && entry.is_hard())
527 {
528 return Some(None);
529 }
530 if let Some(index) = self
531 .active
532 .iter()
533 .position(|entry| entry.identity() == handle.identity() && entry.is_hard())
534 {
535 let mut entry = self.active.remove(index);
536 let deadline = entry.disarm();
537 self.inactive.push(entry);
538 return Some(Some(deadline));
539 }
540 if let Some(executing) = self
541 .executing
542 .iter_mut()
543 .find(|entry| entry.identity == handle.identity())
544 {
545 if executing.disposition != ExecutingKernelTimerDisposition::Destroy {
546 executing.disposition = ExecutingKernelTimerDisposition::Disarm;
547 }
548 return Some(None);
549 }
550 None
551 }
552
553 pub(crate) fn expire_due_soft(
554 &mut self,
555 now: MonotonicInstant,
556 budget: usize,
557 ) -> KernelTimerExpireBatch {
558 let mut expired = 0;
559 while expired < budget {
560 let Some(index) = self.next_active_index(false) else {
561 break;
562 };
563 if !now.reached(self.active[index].deadline()) {
564 break;
565 }
566 let mut entry = self.active.remove(index);
567 entry.expire(now);
568 self.expired.push(entry);
569 expired += 1;
570 }
571 KernelTimerExpireBatch {
572 expired,
573 pending: self.has_due_soft(now),
574 }
575 }
576
577 pub(crate) fn claim_due_hard(&mut self, now: MonotonicInstant) -> Option<KernelTimerExecution> {
578 let index = self.next_active_index(true)?;
579 if !now.reached(self.active[index].deadline()) {
580 return None;
581 }
582 let mut entry = self.active.remove(index);
583 entry.expire(now);
584 self.executing.push(ExecutingKernelTimer {
585 identity: entry.identity(),
586 disposition: ExecutingKernelTimerDisposition::Continue,
587 });
588 Some(KernelTimerExecution { entry })
589 }
590
591 pub(crate) fn claim_expired(&mut self) -> Option<KernelTimerExecution> {
592 if self.expired.is_empty() {
593 return None;
594 }
595 let entry = self.expired.remove(0);
596 self.executing.push(ExecutingKernelTimer {
597 identity: entry.identity(),
598 disposition: ExecutingKernelTimerDisposition::Continue,
599 });
600 Some(KernelTimerExecution { entry })
601 }
602
603 pub(crate) fn complete_soft_execution(
604 &mut self,
605 mut execution: KernelTimerExecution,
606 action: KernelTimerAction,
607 ) -> Option<KernelTimerEntry> {
608 assert!(!execution.is_hard());
609 let position = self
610 .executing
611 .iter()
612 .position(|entry| entry.identity == execution.entry.identity())
613 .expect("completed kernel timer must remain in executing state");
614 let executing = self.executing.swap_remove(position);
615 if executing.disposition == ExecutingKernelTimerDisposition::Continue
616 && let KernelTimerAction::Rearm(deadline) = action
617 {
618 execution.entry.rearm(deadline);
619 self.insert_at(execution.entry);
620 return None;
621 }
622 Some(execution.entry)
623 }
624
625 pub(crate) fn complete_hard_execution(
629 &mut self,
630 mut execution: KernelTimerExecution,
631 action: HardKernelTimerAction,
632 ) -> bool {
633 assert!(execution.is_hard());
634 let position = self
635 .executing
636 .iter()
637 .position(|entry| entry.identity == execution.entry.identity())
638 .expect("completed hard kernel timer must remain in executing state");
639 let executing = self.executing.swap_remove(position);
640 match (executing.disposition, action) {
641 (ExecutingKernelTimerDisposition::Destroy, _) => {
642 self.completed.push(execution.entry);
643 true
644 }
645 (ExecutingKernelTimerDisposition::Disarm, _) => {
646 execution.entry.disarm();
647 self.inactive.push(execution.entry);
648 false
649 }
650 (ExecutingKernelTimerDisposition::Rearm(deadline), _) => {
651 execution.entry.rearm(deadline);
652 self.insert_at(execution.entry);
653 false
654 }
655 (ExecutingKernelTimerDisposition::Continue, HardKernelTimerAction::Complete) => {
656 self.completed.push(execution.entry);
657 true
658 }
659 (ExecutingKernelTimerDisposition::Continue, HardKernelTimerAction::Disarm) => {
660 execution.entry.disarm();
661 self.inactive.push(execution.entry);
662 false
663 }
664 (ExecutingKernelTimerDisposition::Continue, HardKernelTimerAction::Rearm(deadline)) => {
665 execution.entry.rearm(deadline);
666 self.insert_at(execution.entry);
667 false
668 }
669 }
670 }
671
672 pub(crate) fn claim_completed(&mut self) -> Option<KernelTimerEntry> {
673 (!self.completed.is_empty()).then(|| self.completed.remove(0))
674 }
675
676 fn insert_at(&mut self, entry: KernelTimerEntry) {
677 debug_assert!(entry.is_armed());
678 let position = self.active.partition_point(|candidate| {
679 (candidate.deadline(), candidate.identity()) > (entry.deadline(), entry.identity())
680 });
681 self.active.insert(position, entry);
682 }
683
684 fn insert_entry(&mut self, entry: KernelTimerEntry) {
685 if entry.is_armed() {
686 self.insert_at(entry);
687 } else {
688 self.inactive.push(entry);
689 }
690 }
691
692 pub(crate) fn next_soft_deadline(&self) -> Option<MonotonicDeadline> {
693 self.next_active_entry(false)
694 .map(KernelTimerEntry::deadline)
695 }
696
697 pub(crate) fn next_hard_deadline(&self) -> Option<MonotonicDeadline> {
698 self.next_active_entry(true).map(KernelTimerEntry::deadline)
699 }
700
701 pub(crate) fn has_due_soft(&self, now: MonotonicInstant) -> bool {
702 self.next_soft_deadline()
703 .is_some_and(|deadline| now.reached(deadline))
704 }
705
706 pub(crate) fn has_expired(&self) -> bool {
707 !self.expired.is_empty()
708 }
709
710 pub(crate) fn has_completed(&self) -> bool {
711 !self.completed.is_empty()
712 }
713
714 #[cfg(test)]
715 pub(crate) fn has_inactive(&self) -> bool {
716 !self.inactive.is_empty()
717 }
718
719 #[cfg(test)]
720 pub(crate) fn has_active_work(&self) -> bool {
721 !self.active.is_empty()
722 || !self.expired.is_empty()
723 || !self.executing.is_empty()
724 || !self.completed.is_empty()
725 }
726
727 fn next_active_index(&self, hard: bool) -> Option<usize> {
728 self.active
729 .iter()
730 .rposition(|entry| entry.is_hard() == hard)
731 }
732
733 fn next_active_entry(&self, hard: bool) -> Option<&KernelTimerEntry> {
734 self.next_active_index(hard)
735 .map(|index| &self.active[index])
736 }
737}
738
739impl fmt::Debug for KernelTimerQueue {
740 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
741 formatter
742 .debug_struct("KernelTimerQueue")
743 .field("active", &self.active)
744 .field("inactive", &self.inactive)
745 .field("expired", &self.expired)
746 .field("executing", &self.executing)
747 .field("completed", &self.completed)
748 .field("capacity", &self.capacity)
749 .finish()
750 }
751}
752
753#[cfg(test)]
754mod tests;