Introduce the `HrTimerExpires` trait to represent types that can be
used as expiration values for high-resolution timers. Define a
required method, `as_nanos()`, which returns the expiration time as a
raw nanosecond value suitable for use with C's hrtimer APIs.
Also extend the `HrTimerMode` to use the `HrTimerExpires` trait.
This refactoring is a preparation for enabling hrtimer code to work
uniformly with both absolute and relative expiration modes.
Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
---
rust/kernel/time.rs | 5 +
rust/kernel/time/hrtimer.rs | 181 ++++++++++++++++++++++++------------
2 files changed, 128 insertions(+), 58 deletions(-)
diff --git a/rust/kernel/time.rs b/rust/kernel/time.rs
index deca2999ced6..ac9551fca14f 100644
--- a/rust/kernel/time.rs
+++ b/rust/kernel/time.rs
@@ -194,6 +194,11 @@ pub fn now() -> Self {
pub fn elapsed(&self) -> Delta {
Self::now() - *self
}
+
+ #[inline]
+ pub(crate) fn as_nanos(&self) -> i64 {
+ self.inner
+ }
}
impl<C: ClockSource> core::ops::Sub for Instant<C> {
diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs
index 24d013e47c7b..55e1825425b6 100644
--- a/rust/kernel/time/hrtimer.rs
+++ b/rust/kernel/time/hrtimer.rs
@@ -67,7 +67,7 @@
//! A `restart` operation on a timer in the **stopped** state is equivalent to a
//! `start` operation.
-use super::ClockSource;
+use super::{ClockSource, Delta, Instant};
use crate::{prelude::*, types::Opaque};
use core::marker::PhantomData;
use pin_init::PinInit;
@@ -413,94 +413,159 @@ fn into_c(self) -> bindings::hrtimer_restart {
}
}
+/// Time representations that can be used as expiration values in [`HrTimer`].
+pub trait HrTimerExpires {
+ /// Converts the expiration time into a nanosecond representation.
+ ///
+ /// This value corresponds to a raw ktime_t value, suitable for passing to kernel
+ /// timer functions. The interpretation (absolute vs relative) depends on the
+ /// associated [HrTimerMode] in use.
+ fn as_nanos(&self) -> i64;
+}
+
+impl<C: ClockSource> HrTimerExpires for Instant<C> {
+ fn as_nanos(&self) -> i64 {
+ Instant::<C>::as_nanos(self)
+ }
+}
+
+impl HrTimerExpires for Delta {
+ fn as_nanos(&self) -> i64 {
+ Delta::as_nanos(self)
+ }
+}
+
/// Operational mode of [`HrTimer`].
pub trait HrTimerMode {
/// The C representation of hrtimer mode.
const C_MODE: bindings::hrtimer_mode;
-}
-/// Timer that expires at a fixed point in time.
-pub struct AbsoluteMode;
+ /// Type representing the clock source.
+ type Clock: ClockSource;
-impl HrTimerMode for AbsoluteMode {
- const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS;
+ /// Type representing the expiration specification (absolute or relative time).
+ type Expires: HrTimerExpires;
}
-/// Timer that expires after a delay from now.
-pub struct RelativeMode;
-
-impl HrTimerMode for RelativeMode {
- const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_REL;
-}
+/// Defines a new `HrTimerMode` implementation with a given expiration type and C mode.
+#[doc(hidden)]
+macro_rules! define_hrtimer_mode {
+ (
+ $(#[$meta:meta])*
+ $vis:vis struct $name:ident<$clock:ident> {
+ c = $mode:ident,
+ expires = $expires:ty
+ }
+ ) => {
+ $(#[$meta])*
+ $vis struct $name<$clock: $crate::time::ClockSource>(
+ ::core::marker::PhantomData<$clock>
+ );
-/// Timer with absolute expiration time, pinned to its current CPU.
-pub struct AbsolutePinnedMode;
+ impl<$clock: $crate::time::ClockSource> $crate::time::hrtimer::HrTimerMode for $name<$clock> {
+ const C_MODE: $crate::bindings::hrtimer_mode =
+ $crate::macros::paste! {$crate::bindings::[<hrtimer_mode_ $mode>]};
-impl HrTimerMode for AbsolutePinnedMode {
- const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS_PINNED;
+ type Clock = $clock;
+ type Expires = $expires;
+ }
+ };
}
-/// Timer with relative expiration time, pinned to its current CPU.
-pub struct RelativePinnedMode;
-
-impl HrTimerMode for RelativePinnedMode {
- const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_REL_PINNED;
+define_hrtimer_mode! {
+ /// Timer that expires at a fixed point in time.
+ pub struct AbsoluteMode<C> {
+ c = HRTIMER_MODE_ABS,
+ expires = Instant<C>
+ }
}
-/// Timer with absolute expiration, handled in soft irq context.
-pub struct AbsoluteSoftMode;
-
-impl HrTimerMode for AbsoluteSoftMode {
- const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS_SOFT;
+define_hrtimer_mode! {
+ /// Timer that expires after a delay from now.
+ pub struct RelativeMode<C> {
+ c = HRTIMER_MODE_REL,
+ expires = Delta
+ }
}
-/// Timer with relative expiration, handled in soft irq context.
-pub struct RelativeSoftMode;
-
-impl HrTimerMode for RelativeSoftMode {
- const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_REL_SOFT;
+define_hrtimer_mode! {
+ /// Timer with absolute expiration time, pinned to its current CPU.
+ pub struct AbsolutePinnedMode<C> {
+ c = HRTIMER_MODE_ABS_PINNED,
+ expires = Instant<C>
+ }
}
-/// Timer with absolute expiration, pinned to CPU and handled in soft irq context.
-pub struct AbsolutePinnedSoftMode;
-
-impl HrTimerMode for AbsolutePinnedSoftMode {
- const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS_PINNED_SOFT;
+define_hrtimer_mode! {
+ /// Timer with relative expiration time, pinned to its current CPU.
+ pub struct RelativePinnedMode<C> {
+ c = HRTIMER_MODE_REL_PINNED,
+ expires = Delta
+ }
}
-/// Timer with relative expiration, pinned to CPU and handled in soft irq context.
-pub struct RelativePinnedSoftMode;
-
-impl HrTimerMode for RelativePinnedSoftMode {
- const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_REL_PINNED_SOFT;
+define_hrtimer_mode! {
+ /// Timer with absolute expiration, handled in soft irq context.
+ pub struct AbsoluteSoftMode<C> {
+ c = HRTIMER_MODE_ABS_SOFT,
+ expires = Instant<C>
+ }
}
-/// Timer with absolute expiration, handled in hard irq context.
-pub struct AbsoluteHardMode;
-
-impl HrTimerMode for AbsoluteHardMode {
- const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS_HARD;
+define_hrtimer_mode! {
+ /// Timer with relative expiration, handled in soft irq context.
+ pub struct RelativeSoftMode<C> {
+ c = HRTIMER_MODE_REL_SOFT,
+ expires = Delta
+ }
}
-/// Timer with relative expiration, handled in hard irq context.
-pub struct RelativeHardMode;
+define_hrtimer_mode! {
+ /// Timer with absolute expiration, pinned to CPU and handled in soft irq context.
+ pub struct AbsolutePinnedSoftMode<C> {
+ c = HRTIMER_MODE_ABS_PINNED_SOFT,
+ expires = Instant<C>
+ }
+}
-impl HrTimerMode for RelativeHardMode {
- const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_REL_HARD;
+define_hrtimer_mode! {
+ /// Timer with absolute expiration, pinned to CPU and handled in soft irq context.
+ pub struct RelativePinnedSoftMode<C> {
+ c = HRTIMER_MODE_REL_PINNED_SOFT,
+ expires = Delta
+ }
}
-/// Timer with absolute expiration, pinned to CPU and handled in hard irq context.
-pub struct AbsolutePinnedHardMode;
+define_hrtimer_mode! {
+ /// Timer with absolute expiration, handled in hard irq context.
+ pub struct AbsoluteHardMode<C> {
+ c = HRTIMER_MODE_ABS_HARD,
+ expires = Instant<C>
+ }
+}
-impl HrTimerMode for AbsolutePinnedHardMode {
- const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS_PINNED_HARD;
+define_hrtimer_mode! {
+ /// Timer with relative expiration, handled in hard irq context.
+ pub struct RelativeHardMode<C> {
+ c = HRTIMER_MODE_REL_HARD,
+ expires = Delta
+ }
}
-/// Timer with relative expiration, pinned to CPU and handled in hard irq context.
-pub struct RelativePinnedHardMode;
+define_hrtimer_mode! {
+ /// Timer with absolute expiration, pinned to CPU and handled in hard irq context.
+ pub struct AbsolutePinnedHardMode<C> {
+ c = HRTIMER_MODE_ABS_PINNED_HARD,
+ expires = Instant<C>
+ }
+}
-impl HrTimerMode for RelativePinnedHardMode {
- const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_REL_PINNED_HARD;
+define_hrtimer_mode! {
+ /// Timer with relative expiration, pinned to CPU and handled in hard irq context.
+ pub struct RelativePinnedHardMode<C> {
+ c = HRTIMER_MODE_REL_PINNED_HARD,
+ expires = Delta
+ }
}
/// Use to implement the [`HasHrTimer<T>`] trait.
--
2.43.0
Hi Tomonori,
Thanks for fixing this.
FUJITA Tomonori <fujita.tomonori@gmail.com> writes:
> Introduce the `HrTimerExpires` trait to represent types that can be
> used as expiration values for high-resolution timers. Define a
> required method, `as_nanos()`, which returns the expiration time as a
> raw nanosecond value suitable for use with C's hrtimer APIs.
>
> Also extend the `HrTimerMode` to use the `HrTimerExpires` trait.
>
> This refactoring is a preparation for enabling hrtimer code to work
> uniformly with both absolute and relative expiration modes.
>
> Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
> ---
> rust/kernel/time.rs | 5 +
> rust/kernel/time/hrtimer.rs | 181 ++++++++++++++++++++++++------------
> 2 files changed, 128 insertions(+), 58 deletions(-)
>
> diff --git a/rust/kernel/time.rs b/rust/kernel/time.rs
> index deca2999ced6..ac9551fca14f 100644
> --- a/rust/kernel/time.rs
> +++ b/rust/kernel/time.rs
> @@ -194,6 +194,11 @@ pub fn now() -> Self {
> pub fn elapsed(&self) -> Delta {
> Self::now() - *self
> }
> +
> + #[inline]
> + pub(crate) fn as_nanos(&self) -> i64 {
> + self.inner
> + }
> }
>
> impl<C: ClockSource> core::ops::Sub for Instant<C> {
> diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs
> index 24d013e47c7b..55e1825425b6 100644
> --- a/rust/kernel/time/hrtimer.rs
> +++ b/rust/kernel/time/hrtimer.rs
<cut>
> +/// Defines a new `HrTimerMode` implementation with a given expiration type and C mode.
> +#[doc(hidden)]
> +macro_rules! define_hrtimer_mode {
> + (
> + $(#[$meta:meta])*
> + $vis:vis struct $name:ident<$clock:ident> {
> + c = $mode:ident,
> + expires = $expires:ty
> + }
> + ) => {
> + $(#[$meta])*
> + $vis struct $name<$clock: $crate::time::ClockSource>(
> + ::core::marker::PhantomData<$clock>
> + );
I think a macro is too much here. The code would be easier to read
without the macro, and the macro does not remove much code here.
Could you try to do the trait implementations without the macro?
Best regards,
Andreas Hindborg
On Fri, 30 May 2025 15:04:00 +0200
Andreas Hindborg <a.hindborg@kernel.org> wrote:
>> +/// Defines a new `HrTimerMode` implementation with a given expiration type and C mode.
>> +#[doc(hidden)]
>> +macro_rules! define_hrtimer_mode {
>> + (
>> + $(#[$meta:meta])*
>> + $vis:vis struct $name:ident<$clock:ident> {
>> + c = $mode:ident,
>> + expires = $expires:ty
>> + }
>> + ) => {
>> + $(#[$meta])*
>> + $vis struct $name<$clock: $crate::time::ClockSource>(
>> + ::core::marker::PhantomData<$clock>
>> + );
>
> I think a macro is too much here. The code would be easier to read
> without the macro, and the macro does not remove much code here.
>
> Could you try to do the trait implementations without the macro?
Something like the following, right? If so, I'll do in the next
version. I'm also fine with that way.
/// Timer that expires at a fixed point in time.
pub struct AbsoluteMode<C: ClockSource>(PhantomData<C>);
impl<C: ClockSource> HrTimerMode for AbsoluteMode<C> {
const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS;
type Clock = C;
type Expires = Instant<C>;
}
instead of
define_hrtimer_mode! {
/// Timer that expires at a fixed point in time.
pub struct AbsoluteMode<C> {
c = HRTIMER_MODE_ABS,
expires = Instant<C>
}
}
"FUJITA Tomonori" <fujita.tomonori@gmail.com> writes:
> On Fri, 30 May 2025 15:04:00 +0200
> Andreas Hindborg <a.hindborg@kernel.org> wrote:
>
>>> +/// Defines a new `HrTimerMode` implementation with a given expiration type and C mode.
>>> +#[doc(hidden)]
>>> +macro_rules! define_hrtimer_mode {
>>> + (
>>> + $(#[$meta:meta])*
>>> + $vis:vis struct $name:ident<$clock:ident> {
>>> + c = $mode:ident,
>>> + expires = $expires:ty
>>> + }
>>> + ) => {
>>> + $(#[$meta])*
>>> + $vis struct $name<$clock: $crate::time::ClockSource>(
>>> + ::core::marker::PhantomData<$clock>
>>> + );
>>
>> I think a macro is too much here. The code would be easier to read
>> without the macro, and the macro does not remove much code here.
>>
>> Could you try to do the trait implementations without the macro?
>
> Something like the following, right? If so, I'll do in the next
> version. I'm also fine with that way.
>
> /// Timer that expires at a fixed point in time.
> pub struct AbsoluteMode<C: ClockSource>(PhantomData<C>);
>
> impl<C: ClockSource> HrTimerMode for AbsoluteMode<C> {
> const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS;
>
> type Clock = C;
> type Expires = Instant<C>;
> }
OK, let's do that then 👍
Best regards,
Andreas Hindborg
© 2016 - 2026 Red Hat, Inc.