diff options
| author | FUJITA Tomonori <fujita.tomonori@gmail.com> | 2025-06-10 22:28:22 +0900 | 
|---|---|---|
| committer | Andreas Hindborg <a.hindborg@kernel.org> | 2025-06-24 19:52:47 +0200 | 
| commit | e0c0ab04f6785abaa71b9b8dc252cb1a2072c225 (patch) | |
| tree | b32661b36faa36ca993ffa3cab2ca69da171fc69 /rust/kernel/time | |
| parent | d9fc00dc73542eef98db74085447c57174ca290d (diff) | |
rust: time: Make HasHrTimer generic over HrTimerMode
Add a `TimerMode` associated type to the `HasHrTimer` trait to
represent the operational mode of the timer, such as absolute or
relative expiration. This new type must implement the `HrTimerMode`
trait, which defines how expiration values are interpreted.
Update the `start()` method to accept an `expires` parameter of type
`<Self::TimerMode as HrTimerMode>::Expires` instead of the fixed `Ktime`.
This enables different timer modes to provide strongly typed expiration
values, such as `Instant<C>` or `Delta`.
The `impl_has_hr_timer` macro is also extended to allow specifying the
`HrTimerMode`. In the following example, it guarantees that the
`start()` method for `Foo` only accepts `Instant<Monotonic>`. Using a
`Delta` or an `Instant` with a different clock source will result in a
compile-time error:
struct Foo {
    #[pin]
    timer: HrTimer<Self>,
}
impl_has_hr_timer! {
    impl HasHrTimer<Self> for Foo {
        mode : AbsoluteMode<Monotonic>,
        field : self.timer
    }
}
This design eliminates runtime mismatches between expires types and
clock sources, and enables stronger type-level guarantees throughout
hrtimer.
Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
Reviewed-by: Andreas Hindborg <a.hindborg@kernel.org>
Link: https://lore.kernel.org/r/20250610132823.3457263-5-fujita.tomonori@gmail.com
[ changed conversion method names to `as_*` - Andreas ]
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
Diffstat (limited to 'rust/kernel/time')
| -rw-r--r-- | rust/kernel/time/hrtimer.rs | 55 | ||||
| -rw-r--r-- | rust/kernel/time/hrtimer/arc.rs | 8 | ||||
| -rw-r--r-- | rust/kernel/time/hrtimer/pin.rs | 8 | ||||
| -rw-r--r-- | rust/kernel/time/hrtimer/pin_mut.rs | 8 | ||||
| -rw-r--r-- | rust/kernel/time/hrtimer/tbox.rs | 8 | 
5 files changed, 66 insertions, 21 deletions
| diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs index cae7aad6e46d..8b15eb374db0 100644 --- a/rust/kernel/time/hrtimer.rs +++ b/rust/kernel/time/hrtimer.rs @@ -98,7 +98,6 @@ impl Ktime {  pub struct HrTimer<T> {      #[pin]      timer: Opaque<bindings::hrtimer>, -    mode: bindings::hrtimer_mode,      _t: PhantomData<T>,  } @@ -112,9 +111,10 @@ unsafe impl<T> Sync for HrTimer<T> {}  impl<T> HrTimer<T> {      /// Return an initializer for a new timer instance. -    pub fn new<U: ClockSource, M: HrTimerMode>() -> impl PinInit<Self> +    pub fn new() -> impl PinInit<Self>      where          T: HrTimerCallback, +        T: HasHrTimer<T>,      {          pin_init!(Self {              // INVARIANT: We initialize `timer` with `hrtimer_setup` below. @@ -126,12 +126,11 @@ impl<T> HrTimer<T> {                      bindings::hrtimer_setup(                          place,                          Some(T::Pointer::run), -                        U::ID, -                        M::C_MODE, +                        <<T as HasHrTimer<T>>::TimerMode as HrTimerMode>::Clock::ID, +                        <T as HasHrTimer<T>>::TimerMode::C_MODE,                      );                  }              }), -            mode: M::C_MODE,              _t: PhantomData,          })      } @@ -193,6 +192,11 @@ impl<T> HrTimer<T> {  /// exist. A timer can be manipulated through any of the handles, and a handle  /// may represent a cancelled timer.  pub trait HrTimerPointer: Sync + Sized { +    /// The operational mode associated with this timer. +    /// +    /// This defines how the expiration value is interpreted. +    type TimerMode: HrTimerMode; +      /// A handle representing a started or restarted timer.      ///      /// If the timer is running or if the timer callback is executing when the @@ -205,7 +209,7 @@ pub trait HrTimerPointer: Sync + Sized {      /// Start the timer with expiry after `expires` time units. If the timer was      /// already running, it is restarted with the new expiry time. -    fn start(self, expires: Ktime) -> Self::TimerHandle; +    fn start(self, expires: <Self::TimerMode as HrTimerMode>::Expires) -> Self::TimerHandle;  }  /// Unsafe version of [`HrTimerPointer`] for situations where leaking the @@ -220,6 +224,11 @@ pub trait HrTimerPointer: Sync + Sized {  /// [`UnsafeHrTimerPointer`] outlives any associated [`HrTimerPointer::TimerHandle`]  /// instances.  pub unsafe trait UnsafeHrTimerPointer: Sync + Sized { +    /// The operational mode associated with this timer. +    /// +    /// This defines how the expiration value is interpreted. +    type TimerMode: HrTimerMode; +      /// A handle representing a running timer.      ///      /// # Safety @@ -236,7 +245,7 @@ pub unsafe trait UnsafeHrTimerPointer: Sync + Sized {      ///      /// Caller promises keep the timer structure alive until the timer is dead.      /// Caller can ensure this by not leaking the returned [`Self::TimerHandle`]. -    unsafe fn start(self, expires: Ktime) -> Self::TimerHandle; +    unsafe fn start(self, expires: <Self::TimerMode as HrTimerMode>::Expires) -> Self::TimerHandle;  }  /// A trait for stack allocated timers. @@ -246,9 +255,14 @@ pub unsafe trait UnsafeHrTimerPointer: Sync + Sized {  /// Implementers must ensure that `start_scoped` does not return until the  /// timer is dead and the timer handler is not running.  pub unsafe trait ScopedHrTimerPointer { +    /// The operational mode associated with this timer. +    /// +    /// This defines how the expiration value is interpreted. +    type TimerMode: HrTimerMode; +      /// Start the timer to run after `expires` time units and immediately      /// after call `f`. When `f` returns, the timer is cancelled. -    fn start_scoped<T, F>(self, expires: Ktime, f: F) -> T +    fn start_scoped<T, F>(self, expires: <Self::TimerMode as HrTimerMode>::Expires, f: F) -> T      where          F: FnOnce() -> T;  } @@ -260,7 +274,13 @@ unsafe impl<T> ScopedHrTimerPointer for T  where      T: UnsafeHrTimerPointer,  { -    fn start_scoped<U, F>(self, expires: Ktime, f: F) -> U +    type TimerMode = T::TimerMode; + +    fn start_scoped<U, F>( +        self, +        expires: <<T as UnsafeHrTimerPointer>::TimerMode as HrTimerMode>::Expires, +        f: F, +    ) -> U      where          F: FnOnce() -> U,      { @@ -335,6 +355,11 @@ pub unsafe trait HrTimerHandle {  /// their documentation. All the methods of this trait must operate on the same  /// field.  pub unsafe trait HasHrTimer<T> { +    /// The operational mode associated with this timer. +    /// +    /// This defines how the expiration value is interpreted. +    type TimerMode: HrTimerMode; +      /// Return a pointer to the [`HrTimer`] within `Self`.      ///      /// This function is useful to get access to the value without creating @@ -382,14 +407,14 @@ pub unsafe trait HasHrTimer<T> {      /// - `this` must point to a valid `Self`.      /// - Caller must ensure that the pointee of `this` lives until the timer      ///   fires or is canceled. -    unsafe fn start(this: *const Self, expires: Ktime) { +    unsafe fn start(this: *const Self, expires: <Self::TimerMode as HrTimerMode>::Expires) {          // SAFETY: By function safety requirement, `this` is a valid `Self`.          unsafe {              bindings::hrtimer_start_range_ns(                  Self::c_timer_ptr(this).cast_mut(), -                expires.to_ns(), +                expires.as_nanos(),                  0, -                (*Self::raw_get_timer(this)).mode, +                <Self::TimerMode as HrTimerMode>::Clock::ID as u32,              );          }      } @@ -568,12 +593,16 @@ macro_rules! impl_has_hr_timer {          impl$({$($generics:tt)*})?              HasHrTimer<$timer_type:ty>              for $self:ty -        { self.$field:ident } +        { +            mode : $mode:ty, +            field : self.$field:ident $(,)? +        }          $($rest:tt)*      ) => {          // SAFETY: This implementation of `raw_get_timer` only compiles if the          // field has the right type.          unsafe impl$(<$($generics)*>)? $crate::time::hrtimer::HasHrTimer<$timer_type> for $self { +            type TimerMode = $mode;              #[inline]              unsafe fn raw_get_timer( diff --git a/rust/kernel/time/hrtimer/arc.rs b/rust/kernel/time/hrtimer/arc.rs index ccf1e66e5b2d..ed490a7a8950 100644 --- a/rust/kernel/time/hrtimer/arc.rs +++ b/rust/kernel/time/hrtimer/arc.rs @@ -4,8 +4,8 @@ use super::HasHrTimer;  use super::HrTimer;  use super::HrTimerCallback;  use super::HrTimerHandle; +use super::HrTimerMode;  use super::HrTimerPointer; -use super::Ktime;  use super::RawHrTimerCallback;  use crate::sync::Arc;  use crate::sync::ArcBorrow; @@ -54,9 +54,13 @@ where      T: HasHrTimer<T>,      T: for<'a> HrTimerCallback<Pointer<'a> = Self>,  { +    type TimerMode = <T as HasHrTimer<T>>::TimerMode;      type TimerHandle = ArcHrTimerHandle<T>; -    fn start(self, expires: Ktime) -> ArcHrTimerHandle<T> { +    fn start( +        self, +        expires: <<T as HasHrTimer<T>>::TimerMode as HrTimerMode>::Expires, +    ) -> ArcHrTimerHandle<T> {          // SAFETY:          //  - We keep `self` alive by wrapping it in a handle below.          //  - Since we generate the pointer passed to `start` from a valid diff --git a/rust/kernel/time/hrtimer/pin.rs b/rust/kernel/time/hrtimer/pin.rs index 293ca9cf058c..550aad28d987 100644 --- a/rust/kernel/time/hrtimer/pin.rs +++ b/rust/kernel/time/hrtimer/pin.rs @@ -4,7 +4,7 @@ use super::HasHrTimer;  use super::HrTimer;  use super::HrTimerCallback;  use super::HrTimerHandle; -use super::Ktime; +use super::HrTimerMode;  use super::RawHrTimerCallback;  use super::UnsafeHrTimerPointer;  use core::pin::Pin; @@ -54,9 +54,13 @@ where      T: HasHrTimer<T>,      T: HrTimerCallback<Pointer<'a> = Self>,  { +    type TimerMode = <T as HasHrTimer<T>>::TimerMode;      type TimerHandle = PinHrTimerHandle<'a, T>; -    unsafe fn start(self, expires: Ktime) -> Self::TimerHandle { +    unsafe fn start( +        self, +        expires: <<T as HasHrTimer<T>>::TimerMode as HrTimerMode>::Expires, +    ) -> Self::TimerHandle {          // Cast to pointer          let self_ptr: *const T = self.get_ref(); diff --git a/rust/kernel/time/hrtimer/pin_mut.rs b/rust/kernel/time/hrtimer/pin_mut.rs index 6033572d35ad..bacd3d5d972a 100644 --- a/rust/kernel/time/hrtimer/pin_mut.rs +++ b/rust/kernel/time/hrtimer/pin_mut.rs @@ -1,7 +1,7 @@  // SPDX-License-Identifier: GPL-2.0  use super::{ -    HasHrTimer, HrTimer, HrTimerCallback, HrTimerHandle, Ktime, RawHrTimerCallback, +    HasHrTimer, HrTimer, HrTimerCallback, HrTimerHandle, HrTimerMode, RawHrTimerCallback,      UnsafeHrTimerPointer,  };  use core::{marker::PhantomData, pin::Pin, ptr::NonNull}; @@ -52,9 +52,13 @@ where      T: HasHrTimer<T>,      T: HrTimerCallback<Pointer<'a> = Self>,  { +    type TimerMode = <T as HasHrTimer<T>>::TimerMode;      type TimerHandle = PinMutHrTimerHandle<'a, T>; -    unsafe fn start(mut self, expires: Ktime) -> Self::TimerHandle { +    unsafe fn start( +        mut self, +        expires: <<T as HasHrTimer<T>>::TimerMode as HrTimerMode>::Expires, +    ) -> Self::TimerHandle {          // SAFETY:          // - We promise not to move out of `self`. We only pass `self`          //   back to the caller as a `Pin<&mut self>`. diff --git a/rust/kernel/time/hrtimer/tbox.rs b/rust/kernel/time/hrtimer/tbox.rs index 29526a5da203..ec08303315f2 100644 --- a/rust/kernel/time/hrtimer/tbox.rs +++ b/rust/kernel/time/hrtimer/tbox.rs @@ -4,8 +4,8 @@ use super::HasHrTimer;  use super::HrTimer;  use super::HrTimerCallback;  use super::HrTimerHandle; +use super::HrTimerMode;  use super::HrTimerPointer; -use super::Ktime;  use super::RawHrTimerCallback;  use crate::prelude::*;  use core::ptr::NonNull; @@ -64,9 +64,13 @@ where      T: for<'a> HrTimerCallback<Pointer<'a> = Pin<Box<T, A>>>,      A: crate::alloc::Allocator,  { +    type TimerMode = <T as HasHrTimer<T>>::TimerMode;      type TimerHandle = BoxHrTimerHandle<T, A>; -    fn start(self, expires: Ktime) -> Self::TimerHandle { +    fn start( +        self, +        expires: <<T as HasHrTimer<T>>::TimerMode as HrTimerMode>::Expires, +    ) -> Self::TimerHandle {          // SAFETY:          //  - We will not move out of this box during timer callback (we pass an          //    immutable reference to the callback). | 
