1 // SPDX-License-Identifier: GPL-2.0 2 3 //! Intrusive high resolution timers. 4 //! 5 //! Allows running timer callbacks without doing allocations at the time of 6 //! starting the timer. For now, only one timer per type is allowed. 7 //! 8 //! # Vocabulary 9 //! 10 //! States: 11 //! 12 //! - Stopped: initialized but not started, or cancelled, or not restarted. 13 //! - Started: initialized and started or restarted. 14 //! - Running: executing the callback. 15 //! 16 //! Operations: 17 //! 18 //! * Start 19 //! * Cancel 20 //! * Restart 21 //! 22 //! Events: 23 //! 24 //! * Expire 25 //! 26 //! ## State Diagram 27 //! 28 //! ```text 29 //! Return NoRestart 30 //! +---------------------------------------------------------------------+ 31 //! | | 32 //! | | 33 //! | | 34 //! | Return Restart | 35 //! | +------------------------+ | 36 //! | | | | 37 //! | | | | 38 //! v v | | 39 //! +-----------------+ Start +------------------+ +--------+-----+--+ 40 //! | +---------------->| | | | 41 //! Init | | | | Expire | | 42 //! --------->| Stopped | | Started +---------->| Running | 43 //! | | Cancel | | | | 44 //! | |<----------------+ | | | 45 //! +-----------------+ +---------------+--+ +-----------------+ 46 //! ^ | 47 //! | | 48 //! +---------+ 49 //! Restart 50 //! ``` 51 //! 52 //! 53 //! A timer is initialized in the **stopped** state. A stopped timer can be 54 //! **started** by the `start` operation, with an **expiry** time. After the 55 //! `start` operation, the timer is in the **started** state. When the timer 56 //! **expires**, the timer enters the **running** state and the handler is 57 //! executed. After the handler has returned, the timer may enter the 58 //! **started* or **stopped** state, depending on the return value of the 59 //! handler. A timer in the **started** or **running** state may be **canceled** 60 //! by the `cancel` operation. A timer that is cancelled enters the **stopped** 61 //! state. 62 //! 63 //! A `cancel` or `restart` operation on a timer in the **running** state takes 64 //! effect after the handler has returned and the timer has transitioned 65 //! out of the **running** state. 66 //! 67 //! A `restart` operation on a timer in the **stopped** state is equivalent to a 68 //! `start` operation. 69 70 use super::{ClockSource, Delta, Instant}; 71 use crate::{prelude::*, types::Opaque}; 72 use core::marker::PhantomData; 73 use pin_init::PinInit; 74 75 /// A Rust wrapper around a `ktime_t`. 76 // NOTE: Ktime is going to be removed when hrtimer is converted to Instant/Delta. 77 #[repr(transparent)] 78 #[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord)] 79 pub struct Ktime { 80 inner: bindings::ktime_t, 81 } 82 83 impl Ktime { 84 /// Returns the number of nanoseconds. 85 #[inline] 86 pub fn to_ns(self) -> i64 { 87 self.inner 88 } 89 } 90 91 /// A timer backed by a C `struct hrtimer`. 92 /// 93 /// # Invariants 94 /// 95 /// * `self.timer` is initialized by `bindings::hrtimer_setup`. 96 #[pin_data] 97 #[repr(C)] 98 pub struct HrTimer<T> { 99 #[pin] 100 timer: Opaque<bindings::hrtimer>, 101 _t: PhantomData<T>, 102 } 103 104 // SAFETY: Ownership of an `HrTimer` can be moved to other threads and 105 // used/dropped from there. 106 unsafe impl<T> Send for HrTimer<T> {} 107 108 // SAFETY: Timer operations are locked on the C side, so it is safe to operate 109 // on a timer from multiple threads. 110 unsafe impl<T> Sync for HrTimer<T> {} 111 112 impl<T> HrTimer<T> { 113 /// Return an initializer for a new timer instance. 114 pub fn new() -> impl PinInit<Self> 115 where 116 T: HrTimerCallback, 117 T: HasHrTimer<T>, 118 { 119 pin_init!(Self { 120 // INVARIANT: We initialize `timer` with `hrtimer_setup` below. 121 timer <- Opaque::ffi_init(move |place: *mut bindings::hrtimer| { 122 // SAFETY: By design of `pin_init!`, `place` is a pointer to a 123 // live allocation. hrtimer_setup will initialize `place` and 124 // does not require `place` to be initialized prior to the call. 125 unsafe { 126 bindings::hrtimer_setup( 127 place, 128 Some(T::Pointer::run), 129 <<T as HasHrTimer<T>>::TimerMode as HrTimerMode>::Clock::ID, 130 <T as HasHrTimer<T>>::TimerMode::C_MODE, 131 ); 132 } 133 }), 134 _t: PhantomData, 135 }) 136 } 137 138 /// Get a pointer to the contained `bindings::hrtimer`. 139 /// 140 /// This function is useful to get access to the value without creating 141 /// intermediate references. 142 /// 143 /// # Safety 144 /// 145 /// `this` must point to a live allocation of at least the size of `Self`. 146 unsafe fn raw_get(this: *const Self) -> *mut bindings::hrtimer { 147 // SAFETY: The field projection to `timer` does not go out of bounds, 148 // because the caller of this function promises that `this` points to an 149 // allocation of at least the size of `Self`. 150 unsafe { Opaque::raw_get(core::ptr::addr_of!((*this).timer)) } 151 } 152 153 /// Cancel an initialized and potentially running timer. 154 /// 155 /// If the timer handler is running, this function will block until the 156 /// handler returns. 157 /// 158 /// Note that the timer might be started by a concurrent start operation. If 159 /// so, the timer might not be in the **stopped** state when this function 160 /// returns. 161 /// 162 /// Users of the `HrTimer` API would not usually call this method directly. 163 /// Instead they would use the safe [`HrTimerHandle::cancel`] on the handle 164 /// returned when the timer was started. 165 /// 166 /// This function is useful to get access to the value without creating 167 /// intermediate references. 168 /// 169 /// # Safety 170 /// 171 /// `this` must point to a valid `Self`. 172 pub(crate) unsafe fn raw_cancel(this: *const Self) -> bool { 173 // SAFETY: `this` points to an allocation of at least `HrTimer` size. 174 let c_timer_ptr = unsafe { HrTimer::raw_get(this) }; 175 176 // If the handler is running, this will wait for the handler to return 177 // before returning. 178 // SAFETY: `c_timer_ptr` is initialized and valid. Synchronization is 179 // handled on the C side. 180 unsafe { bindings::hrtimer_cancel(c_timer_ptr) != 0 } 181 } 182 } 183 184 /// Implemented by pointer types that point to structs that contain a [`HrTimer`]. 185 /// 186 /// `Self` must be [`Sync`] because it is passed to timer callbacks in another 187 /// thread of execution (hard or soft interrupt context). 188 /// 189 /// Starting a timer returns a [`HrTimerHandle`] that can be used to manipulate 190 /// the timer. Note that it is OK to call the start function repeatedly, and 191 /// that more than one [`HrTimerHandle`] associated with a [`HrTimerPointer`] may 192 /// exist. A timer can be manipulated through any of the handles, and a handle 193 /// may represent a cancelled timer. 194 pub trait HrTimerPointer: Sync + Sized { 195 /// The operational mode associated with this timer. 196 /// 197 /// This defines how the expiration value is interpreted. 198 type TimerMode: HrTimerMode; 199 200 /// A handle representing a started or restarted timer. 201 /// 202 /// If the timer is running or if the timer callback is executing when the 203 /// handle is dropped, the drop method of [`HrTimerHandle`] should not return 204 /// until the timer is stopped and the callback has completed. 205 /// 206 /// Note: When implementing this trait, consider that it is not unsafe to 207 /// leak the handle. 208 type TimerHandle: HrTimerHandle; 209 210 /// Start the timer with expiry after `expires` time units. If the timer was 211 /// already running, it is restarted with the new expiry time. 212 fn start(self, expires: <Self::TimerMode as HrTimerMode>::Expires) -> Self::TimerHandle; 213 } 214 215 /// Unsafe version of [`HrTimerPointer`] for situations where leaking the 216 /// [`HrTimerHandle`] returned by `start` would be unsound. This is the case for 217 /// stack allocated timers. 218 /// 219 /// Typical implementers are pinned references such as [`Pin<&T>`]. 220 /// 221 /// # Safety 222 /// 223 /// Implementers of this trait must ensure that instances of types implementing 224 /// [`UnsafeHrTimerPointer`] outlives any associated [`HrTimerPointer::TimerHandle`] 225 /// instances. 226 pub unsafe trait UnsafeHrTimerPointer: Sync + Sized { 227 /// The operational mode associated with this timer. 228 /// 229 /// This defines how the expiration value is interpreted. 230 type TimerMode: HrTimerMode; 231 232 /// A handle representing a running timer. 233 /// 234 /// # Safety 235 /// 236 /// If the timer is running, or if the timer callback is executing when the 237 /// handle is dropped, the drop method of [`Self::TimerHandle`] must not return 238 /// until the timer is stopped and the callback has completed. 239 type TimerHandle: HrTimerHandle; 240 241 /// Start the timer after `expires` time units. If the timer was already 242 /// running, it is restarted at the new expiry time. 243 /// 244 /// # Safety 245 /// 246 /// Caller promises keep the timer structure alive until the timer is dead. 247 /// Caller can ensure this by not leaking the returned [`Self::TimerHandle`]. 248 unsafe fn start(self, expires: <Self::TimerMode as HrTimerMode>::Expires) -> Self::TimerHandle; 249 } 250 251 /// A trait for stack allocated timers. 252 /// 253 /// # Safety 254 /// 255 /// Implementers must ensure that `start_scoped` does not return until the 256 /// timer is dead and the timer handler is not running. 257 pub unsafe trait ScopedHrTimerPointer { 258 /// The operational mode associated with this timer. 259 /// 260 /// This defines how the expiration value is interpreted. 261 type TimerMode: HrTimerMode; 262 263 /// Start the timer to run after `expires` time units and immediately 264 /// after call `f`. When `f` returns, the timer is cancelled. 265 fn start_scoped<T, F>(self, expires: <Self::TimerMode as HrTimerMode>::Expires, f: F) -> T 266 where 267 F: FnOnce() -> T; 268 } 269 270 // SAFETY: By the safety requirement of [`UnsafeHrTimerPointer`], dropping the 271 // handle returned by [`UnsafeHrTimerPointer::start`] ensures that the timer is 272 // killed. 273 unsafe impl<T> ScopedHrTimerPointer for T 274 where 275 T: UnsafeHrTimerPointer, 276 { 277 type TimerMode = T::TimerMode; 278 279 fn start_scoped<U, F>( 280 self, 281 expires: <<T as UnsafeHrTimerPointer>::TimerMode as HrTimerMode>::Expires, 282 f: F, 283 ) -> U 284 where 285 F: FnOnce() -> U, 286 { 287 // SAFETY: We drop the timer handle below before returning. 288 let handle = unsafe { UnsafeHrTimerPointer::start(self, expires) }; 289 let t = f(); 290 drop(handle); 291 t 292 } 293 } 294 295 /// Implemented by [`HrTimerPointer`] implementers to give the C timer callback a 296 /// function to call. 297 // This is split from `HrTimerPointer` to make it easier to specify trait bounds. 298 pub trait RawHrTimerCallback { 299 /// Type of the parameter passed to [`HrTimerCallback::run`]. It may be 300 /// [`Self`], or a pointer type derived from [`Self`]. 301 type CallbackTarget<'a>; 302 303 /// Callback to be called from C when timer fires. 304 /// 305 /// # Safety 306 /// 307 /// Only to be called by C code in the `hrtimer` subsystem. `this` must point 308 /// to the `bindings::hrtimer` structure that was used to start the timer. 309 unsafe extern "C" fn run(this: *mut bindings::hrtimer) -> bindings::hrtimer_restart; 310 } 311 312 /// Implemented by structs that can be the target of a timer callback. 313 pub trait HrTimerCallback { 314 /// The type whose [`RawHrTimerCallback::run`] method will be invoked when 315 /// the timer expires. 316 type Pointer<'a>: RawHrTimerCallback; 317 318 /// Called by the timer logic when the timer fires. 319 fn run(this: <Self::Pointer<'_> as RawHrTimerCallback>::CallbackTarget<'_>) -> HrTimerRestart 320 where 321 Self: Sized; 322 } 323 324 /// A handle representing a potentially running timer. 325 /// 326 /// More than one handle representing the same timer might exist. 327 /// 328 /// # Safety 329 /// 330 /// When dropped, the timer represented by this handle must be cancelled, if it 331 /// is running. If the timer handler is running when the handle is dropped, the 332 /// drop method must wait for the handler to return before returning. 333 /// 334 /// Note: One way to satisfy the safety requirement is to call `Self::cancel` in 335 /// the drop implementation for `Self.` 336 pub unsafe trait HrTimerHandle { 337 /// Cancel the timer. If the timer is in the running state, block till the 338 /// handler has returned. 339 /// 340 /// Note that the timer might be started by a concurrent start operation. If 341 /// so, the timer might not be in the **stopped** state when this function 342 /// returns. 343 fn cancel(&mut self) -> bool; 344 } 345 346 /// Implemented by structs that contain timer nodes. 347 /// 348 /// Clients of the timer API would usually safely implement this trait by using 349 /// the [`crate::impl_has_hr_timer`] macro. 350 /// 351 /// # Safety 352 /// 353 /// Implementers of this trait must ensure that the implementer has a 354 /// [`HrTimer`] field and that all trait methods are implemented according to 355 /// their documentation. All the methods of this trait must operate on the same 356 /// field. 357 pub unsafe trait HasHrTimer<T> { 358 /// The operational mode associated with this timer. 359 /// 360 /// This defines how the expiration value is interpreted. 361 type TimerMode: HrTimerMode; 362 363 /// Return a pointer to the [`HrTimer`] within `Self`. 364 /// 365 /// This function is useful to get access to the value without creating 366 /// intermediate references. 367 /// 368 /// # Safety 369 /// 370 /// `this` must be a valid pointer. 371 unsafe fn raw_get_timer(this: *const Self) -> *const HrTimer<T>; 372 373 /// Return a pointer to the struct that is containing the [`HrTimer`] pointed 374 /// to by `ptr`. 375 /// 376 /// This function is useful to get access to the value without creating 377 /// intermediate references. 378 /// 379 /// # Safety 380 /// 381 /// `ptr` must point to a [`HrTimer<T>`] field in a struct of type `Self`. 382 unsafe fn timer_container_of(ptr: *mut HrTimer<T>) -> *mut Self 383 where 384 Self: Sized; 385 386 /// Get pointer to the contained `bindings::hrtimer` struct. 387 /// 388 /// This function is useful to get access to the value without creating 389 /// intermediate references. 390 /// 391 /// # Safety 392 /// 393 /// `this` must be a valid pointer. 394 unsafe fn c_timer_ptr(this: *const Self) -> *const bindings::hrtimer { 395 // SAFETY: `this` is a valid pointer to a `Self`. 396 let timer_ptr = unsafe { Self::raw_get_timer(this) }; 397 398 // SAFETY: timer_ptr points to an allocation of at least `HrTimer` size. 399 unsafe { HrTimer::raw_get(timer_ptr) } 400 } 401 402 /// Start the timer contained in the `Self` pointed to by `self_ptr`. If 403 /// it is already running it is removed and inserted. 404 /// 405 /// # Safety 406 /// 407 /// - `this` must point to a valid `Self`. 408 /// - Caller must ensure that the pointee of `this` lives until the timer 409 /// fires or is canceled. 410 unsafe fn start(this: *const Self, expires: <Self::TimerMode as HrTimerMode>::Expires) { 411 // SAFETY: By function safety requirement, `this` is a valid `Self`. 412 unsafe { 413 bindings::hrtimer_start_range_ns( 414 Self::c_timer_ptr(this).cast_mut(), 415 expires.as_nanos(), 416 0, 417 <Self::TimerMode as HrTimerMode>::Clock::ID as u32, 418 ); 419 } 420 } 421 } 422 423 /// Restart policy for timers. 424 #[derive(Copy, Clone, PartialEq, Eq, Debug)] 425 #[repr(u32)] 426 pub enum HrTimerRestart { 427 /// Timer should not be restarted. 428 NoRestart = bindings::hrtimer_restart_HRTIMER_NORESTART, 429 /// Timer should be restarted. 430 Restart = bindings::hrtimer_restart_HRTIMER_RESTART, 431 } 432 433 impl HrTimerRestart { 434 fn into_c(self) -> bindings::hrtimer_restart { 435 self as bindings::hrtimer_restart 436 } 437 } 438 439 /// Time representations that can be used as expiration values in [`HrTimer`]. 440 pub trait HrTimerExpires { 441 /// Converts the expiration time into a nanosecond representation. 442 /// 443 /// This value corresponds to a raw ktime_t value, suitable for passing to kernel 444 /// timer functions. The interpretation (absolute vs relative) depends on the 445 /// associated [HrTimerMode] in use. 446 fn as_nanos(&self) -> i64; 447 } 448 449 impl<C: ClockSource> HrTimerExpires for Instant<C> { 450 #[inline] 451 fn as_nanos(&self) -> i64 { 452 Instant::<C>::as_nanos(self) 453 } 454 } 455 456 impl HrTimerExpires for Delta { 457 #[inline] 458 fn as_nanos(&self) -> i64 { 459 Delta::as_nanos(*self) 460 } 461 } 462 463 /// Operational mode of [`HrTimer`]. 464 pub trait HrTimerMode { 465 /// The C representation of hrtimer mode. 466 const C_MODE: bindings::hrtimer_mode; 467 468 /// Type representing the clock source. 469 type Clock: ClockSource; 470 471 /// Type representing the expiration specification (absolute or relative time). 472 type Expires: HrTimerExpires; 473 } 474 475 /// Timer that expires at a fixed point in time. 476 pub struct AbsoluteMode<C: ClockSource>(PhantomData<C>); 477 478 impl<C: ClockSource> HrTimerMode for AbsoluteMode<C> { 479 const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS; 480 481 type Clock = C; 482 type Expires = Instant<C>; 483 } 484 485 /// Timer that expires after a delay from now. 486 pub struct RelativeMode<C: ClockSource>(PhantomData<C>); 487 488 impl<C: ClockSource> HrTimerMode for RelativeMode<C> { 489 const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_REL; 490 491 type Clock = C; 492 type Expires = Delta; 493 } 494 495 /// Timer with absolute expiration time, pinned to its current CPU. 496 pub struct AbsolutePinnedMode<C: ClockSource>(PhantomData<C>); 497 impl<C: ClockSource> HrTimerMode for AbsolutePinnedMode<C> { 498 const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS_PINNED; 499 500 type Clock = C; 501 type Expires = Instant<C>; 502 } 503 504 /// Timer with relative expiration time, pinned to its current CPU. 505 pub struct RelativePinnedMode<C: ClockSource>(PhantomData<C>); 506 impl<C: ClockSource> HrTimerMode for RelativePinnedMode<C> { 507 const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_REL_PINNED; 508 509 type Clock = C; 510 type Expires = Delta; 511 } 512 513 /// Timer with absolute expiration, handled in soft irq context. 514 pub struct AbsoluteSoftMode<C: ClockSource>(PhantomData<C>); 515 impl<C: ClockSource> HrTimerMode for AbsoluteSoftMode<C> { 516 const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS_SOFT; 517 518 type Clock = C; 519 type Expires = Instant<C>; 520 } 521 522 /// Timer with relative expiration, handled in soft irq context. 523 pub struct RelativeSoftMode<C: ClockSource>(PhantomData<C>); 524 impl<C: ClockSource> HrTimerMode for RelativeSoftMode<C> { 525 const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_REL_SOFT; 526 527 type Clock = C; 528 type Expires = Delta; 529 } 530 531 /// Timer with absolute expiration, pinned to CPU and handled in soft irq context. 532 pub struct AbsolutePinnedSoftMode<C: ClockSource>(PhantomData<C>); 533 impl<C: ClockSource> HrTimerMode for AbsolutePinnedSoftMode<C> { 534 const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS_PINNED_SOFT; 535 536 type Clock = C; 537 type Expires = Instant<C>; 538 } 539 540 /// Timer with absolute expiration, pinned to CPU and handled in soft irq context. 541 pub struct RelativePinnedSoftMode<C: ClockSource>(PhantomData<C>); 542 impl<C: ClockSource> HrTimerMode for RelativePinnedSoftMode<C> { 543 const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_REL_PINNED_SOFT; 544 545 type Clock = C; 546 type Expires = Delta; 547 } 548 549 /// Timer with absolute expiration, handled in hard irq context. 550 pub struct AbsoluteHardMode<C: ClockSource>(PhantomData<C>); 551 impl<C: ClockSource> HrTimerMode for AbsoluteHardMode<C> { 552 const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS_HARD; 553 554 type Clock = C; 555 type Expires = Instant<C>; 556 } 557 558 /// Timer with relative expiration, handled in hard irq context. 559 pub struct RelativeHardMode<C: ClockSource>(PhantomData<C>); 560 impl<C: ClockSource> HrTimerMode for RelativeHardMode<C> { 561 const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_REL_HARD; 562 563 type Clock = C; 564 type Expires = Delta; 565 } 566 567 /// Timer with absolute expiration, pinned to CPU and handled in hard irq context. 568 pub struct AbsolutePinnedHardMode<C: ClockSource>(PhantomData<C>); 569 impl<C: ClockSource> HrTimerMode for AbsolutePinnedHardMode<C> { 570 const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS_PINNED_HARD; 571 572 type Clock = C; 573 type Expires = Instant<C>; 574 } 575 576 /// Timer with relative expiration, pinned to CPU and handled in hard irq context. 577 pub struct RelativePinnedHardMode<C: ClockSource>(PhantomData<C>); 578 impl<C: ClockSource> HrTimerMode for RelativePinnedHardMode<C> { 579 const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_REL_PINNED_HARD; 580 581 type Clock = C; 582 type Expires = Delta; 583 } 584 585 /// Use to implement the [`HasHrTimer<T>`] trait. 586 /// 587 /// See [`module`] documentation for an example. 588 /// 589 /// [`module`]: crate::time::hrtimer 590 #[macro_export] 591 macro_rules! impl_has_hr_timer { 592 ( 593 impl$({$($generics:tt)*})? 594 HasHrTimer<$timer_type:ty> 595 for $self:ty 596 { 597 mode : $mode:ty, 598 field : self.$field:ident $(,)? 599 } 600 $($rest:tt)* 601 ) => { 602 // SAFETY: This implementation of `raw_get_timer` only compiles if the 603 // field has the right type. 604 unsafe impl$(<$($generics)*>)? $crate::time::hrtimer::HasHrTimer<$timer_type> for $self { 605 type TimerMode = $mode; 606 607 #[inline] 608 unsafe fn raw_get_timer( 609 this: *const Self, 610 ) -> *const $crate::time::hrtimer::HrTimer<$timer_type> { 611 // SAFETY: The caller promises that the pointer is not dangling. 612 unsafe { ::core::ptr::addr_of!((*this).$field) } 613 } 614 615 #[inline] 616 unsafe fn timer_container_of( 617 ptr: *mut $crate::time::hrtimer::HrTimer<$timer_type>, 618 ) -> *mut Self { 619 // SAFETY: As per the safety requirement of this function, `ptr` 620 // is pointing inside a `$timer_type`. 621 unsafe { ::kernel::container_of!(ptr, $timer_type, $field) } 622 } 623 } 624 } 625 } 626 627 mod arc; 628 pub use arc::ArcHrTimerHandle; 629 mod pin; 630 pub use pin::PinHrTimerHandle; 631 mod pin_mut; 632 pub use pin_mut::PinMutHrTimerHandle; 633 // `box` is a reserved keyword, so prefix with `t` for timer 634 mod tbox; 635 pub use tbox::BoxHrTimerHandle; 636