[PATCH v3] hrtimer: add usage examples to documentation

Andreas Hindborg posted 1 patch 1 month, 3 weeks ago
rust/kernel/time/hrtimer.rs | 336 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 336 insertions(+)
[PATCH v3] hrtimer: add usage examples to documentation
Posted by Andreas Hindborg 1 month, 3 weeks ago
Add documentation examples showing various ways to use hrtimers:

- Box-allocated timers with shared state in Arc.
- Arc-allocated timers.
- Stack-based timers for scoped usage.
- Mutable stack-based timers with shared state.

Tested-by: Daniel Almeida <daniel.almeida@collabora.com>
Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
Changes in v3:
- Do not hide imports in examples.
- Link to v2: https://msgid.link/20260219-hrtimer-examples-v6-19-rc1-v2-1-810cc06ca9f6@kernel.org

Changes in v2:
- Sprinkle blank lines for readability
- Change heading for Arc example
- Fix error handling.
- Link to v1: https://lore.kernel.org/r/20251217-hrtimer-examples-v6-19-rc1-v1-1-4ad0e7e4c4e0@kernel.org
---
 rust/kernel/time/hrtimer.rs | 336 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 336 insertions(+)

diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs
index 856d2d929a008..0362bb8492716 100644
--- a/rust/kernel/time/hrtimer.rs
+++ b/rust/kernel/time/hrtimer.rs
@@ -66,6 +66,342 @@
 //!
 //! A `restart` operation on a timer in the **stopped** state is equivalent to a
 //! `start` operation.
+//!
+//! When a type implements both `HrTimerPointer` and `Clone`, it is possible to
+//! issue the `start` operation while the timer is in the **started** state. In
+//! this case the `start` operation is equivalent to the `restart` operation.
+//!
+//! # Examples
+//!
+//! ## Using an intrusive timer living in a [`Box`]
+//!
+//! ```
+//! use kernel::{
+//!     alloc::flags,
+//!     impl_has_hr_timer,
+//!     prelude::*,
+//!     sync::{
+//!         atomic::{ordering, Atomic},
+//!         completion::Completion,
+//!         Arc,
+//!     },
+//!     time::{
+//!         hrtimer::{
+//!             RelativeMode, HrTimer, HrTimerCallback, HrTimerPointer,
+//!             HrTimerRestart, HrTimerCallbackContext
+//!         },
+//!         Delta, Monotonic,
+//!     },
+//! };
+//!
+//! #[pin_data]
+//! struct Shared {
+//!     #[pin]
+//!     flag: Atomic<u64>,
+//!     #[pin]
+//!     cond: Completion,
+//! }
+//!
+//! impl Shared {
+//!     fn new() -> impl PinInit<Self> {
+//!         pin_init!(Self {
+//!             flag <- Atomic::new(0),
+//!             cond <- Completion::new(),
+//!         })
+//!     }
+//! }
+//!
+//! #[pin_data]
+//! struct BoxIntrusiveHrTimer {
+//!     #[pin]
+//!     timer: HrTimer<Self>,
+//!     shared: Arc<Shared>,
+//! }
+//!
+//! impl BoxIntrusiveHrTimer {
+//!     fn new() -> impl PinInit<Self, kernel::error::Error> {
+//!         try_pin_init!(Self {
+//!             timer <- HrTimer::new(),
+//!             shared: Arc::pin_init(Shared::new(), flags::GFP_KERNEL)?,
+//!         })
+//!     }
+//! }
+//!
+//! impl HrTimerCallback for BoxIntrusiveHrTimer {
+//!     type Pointer<'a> = Pin<KBox<Self>>;
+//!
+//!     fn run(this: Pin<&mut Self>, _ctx: HrTimerCallbackContext<'_, Self>) -> HrTimerRestart {
+//!         pr_info!("Timer called\n");
+//!
+//!         let flag = this.shared.flag.fetch_add(1, ordering::Full);
+//!         this.shared.cond.complete_all();
+//!
+//!         if flag == 4 {
+//!             HrTimerRestart::NoRestart
+//!         } else {
+//!             HrTimerRestart::Restart
+//!         }
+//!     }
+//! }
+//!
+//! impl_has_hr_timer! {
+//!     impl HasHrTimer<Self> for BoxIntrusiveHrTimer {
+//!         mode: RelativeMode<Monotonic>, field: self.timer
+//!     }
+//! }
+//!
+//! let has_timer = Box::pin_init(BoxIntrusiveHrTimer::new(), GFP_KERNEL)?;
+//! let shared = has_timer.shared.clone();
+//! let _handle = has_timer.start(Delta::from_micros(200));
+//!
+//! while shared.flag.load(ordering::Relaxed) != 5 {
+//!     shared.cond.wait_for_completion();
+//! }
+//!
+//! pr_info!("Counted to 5\n");
+//! # Ok::<(), kernel::error::Error>(())
+//! ```
+//!
+//! ## Using an intrusive timer in an [`Arc`]
+//!
+//! ```
+//! use kernel::{
+//!     alloc::flags,
+//!     impl_has_hr_timer,
+//!     prelude::*,
+//!     sync::{
+//!         atomic::{ordering, Atomic},
+//!         completion::Completion,
+//!         Arc, ArcBorrow,
+//!     },
+//!     time::{
+//!         hrtimer::{
+//!             RelativeMode, HrTimer, HrTimerCallback, HrTimerPointer, HrTimerRestart,
+//!             HasHrTimer, HrTimerCallbackContext
+//!         },
+//!         Delta, Monotonic,
+//!     },
+//! };
+//!
+//! #[pin_data]
+//! struct ArcIntrusiveHrTimer {
+//!     #[pin]
+//!     timer: HrTimer<Self>,
+//!     #[pin]
+//!     flag: Atomic<u64>,
+//!     #[pin]
+//!     cond: Completion,
+//! }
+//!
+//! impl ArcIntrusiveHrTimer {
+//!     fn new() -> impl PinInit<Self> {
+//!         pin_init!(Self {
+//!             timer <- HrTimer::new(),
+//!             flag <- Atomic::new(0),
+//!             cond <- Completion::new(),
+//!         })
+//!     }
+//! }
+//!
+//! impl HrTimerCallback for ArcIntrusiveHrTimer {
+//!     type Pointer<'a> = Arc<Self>;
+//!
+//!     fn run(
+//!         this: ArcBorrow<'_, Self>,
+//!         _ctx: HrTimerCallbackContext<'_, Self>,
+//!     ) -> HrTimerRestart {
+//!         pr_info!("Timer called\n");
+//!
+//!         let flag = this.flag.fetch_add(1, ordering::Full);
+//!         this.cond.complete_all();
+//!
+//!         if flag == 4 {
+//!             HrTimerRestart::NoRestart
+//!         } else {
+//!             HrTimerRestart::Restart
+//!         }
+//!     }
+//! }
+//!
+//! impl_has_hr_timer! {
+//!     impl HasHrTimer<Self> for ArcIntrusiveHrTimer {
+//!         mode: RelativeMode<Monotonic>, field: self.timer
+//!     }
+//! }
+//!
+//! let has_timer = Arc::pin_init(ArcIntrusiveHrTimer::new(), GFP_KERNEL)?;
+//! let _handle = has_timer.clone().start(Delta::from_micros(200));
+//!
+//! while has_timer.flag.load(ordering::Relaxed) != 5 {
+//!     has_timer.cond.wait_for_completion();
+//! }
+//!
+//! pr_info!("Counted to 5\n");
+//! # Ok::<(), kernel::error::Error>(())
+//! ```
+//!
+//! ## Using a stack-based timer
+//!
+//! ```
+//! use kernel::{
+//!     impl_has_hr_timer,
+//!     prelude::*,
+//!     sync::{
+//!         atomic::{ordering, Atomic},
+//!         completion::Completion,
+//!     },
+//!     time::{
+//!         hrtimer::{
+//!             ScopedHrTimerPointer, HrTimer, HrTimerCallback, HrTimerPointer, HrTimerRestart,
+//!             HasHrTimer, RelativeMode, HrTimerCallbackContext
+//!         },
+//!         Delta, Monotonic,
+//!     },
+//! };
+//! use pin_init::stack_pin_init;
+//!
+//! #[pin_data]
+//! struct IntrusiveHrTimer {
+//!     #[pin]
+//!     timer: HrTimer<Self>,
+//!     #[pin]
+//!     flag: Atomic<u64>,
+//!     #[pin]
+//!     cond: Completion,
+//! }
+//!
+//! impl IntrusiveHrTimer {
+//!     fn new() -> impl PinInit<Self> {
+//!         pin_init!(Self {
+//!             timer <- HrTimer::new(),
+//!             flag <- Atomic::new(0),
+//!             cond <- Completion::new(),
+//!         })
+//!     }
+//! }
+//!
+//! impl HrTimerCallback for IntrusiveHrTimer {
+//!     type Pointer<'a> = Pin<&'a Self>;
+//!
+//!     fn run(this: Pin<&Self>, _ctx: HrTimerCallbackContext<'_, Self>) -> HrTimerRestart {
+//!         pr_info!("Timer called\n");
+//!
+//!         this.flag.store(1, ordering::Release);
+//!         this.cond.complete_all();
+//!
+//!         HrTimerRestart::NoRestart
+//!     }
+//! }
+//!
+//! impl_has_hr_timer! {
+//!     impl HasHrTimer<Self> for IntrusiveHrTimer {
+//!         mode: RelativeMode<Monotonic>, field: self.timer
+//!     }
+//! }
+//!
+//! stack_pin_init!( let has_timer = IntrusiveHrTimer::new() );
+//! has_timer.as_ref().start_scoped(Delta::from_micros(200), || {
+//!     while has_timer.flag.load(ordering::Relaxed) != 1 {
+//!         has_timer.cond.wait_for_completion();
+//!     }
+//! });
+//!
+//! pr_info!("Flag raised\n");
+//! # Ok::<(), kernel::error::Error>(())
+//! ```
+//!
+//! ## Using a mutable stack-based timer
+//!
+//! ```
+//! use kernel::{
+//!     alloc::flags,
+//!     impl_has_hr_timer,
+//!     prelude::*,
+//!     sync::{
+//!         atomic::{ordering, Atomic},
+//!         completion::Completion,
+//!         Arc,
+//!     },
+//!     time::{
+//!         hrtimer::{
+//!             ScopedHrTimerPointer, HrTimer, HrTimerCallback, HrTimerPointer, HrTimerRestart,
+//!             HasHrTimer, RelativeMode, HrTimerCallbackContext
+//!         },
+//!         Delta, Monotonic,
+//!     },
+//! };
+//! use pin_init::stack_try_pin_init;
+//!
+//! #[pin_data]
+//! struct Shared {
+//!     #[pin]
+//!     flag: Atomic<u64>,
+//!     #[pin]
+//!     cond: Completion,
+//! }
+//!
+//! impl Shared {
+//!     fn new() -> impl PinInit<Self> {
+//!         pin_init!(Self {
+//!             flag <- Atomic::new(0),
+//!             cond <- Completion::new(),
+//!         })
+//!     }
+//! }
+//!
+//! #[pin_data]
+//! struct IntrusiveHrTimer {
+//!     #[pin]
+//!     timer: HrTimer<Self>,
+//!     shared: Arc<Shared>,
+//! }
+//!
+//! impl IntrusiveHrTimer {
+//!     fn new() -> impl PinInit<Self, kernel::error::Error> {
+//!         try_pin_init!(Self {
+//!             timer <- HrTimer::new(),
+//!             shared: Arc::pin_init(Shared::new(), flags::GFP_KERNEL)?,
+//!         })
+//!     }
+//! }
+//!
+//! impl HrTimerCallback for IntrusiveHrTimer {
+//!     type Pointer<'a> = Pin<&'a mut Self>;
+//!
+//!     fn run(this: Pin<&mut Self>, _ctx: HrTimerCallbackContext<'_, Self>) -> HrTimerRestart {
+//!         pr_info!("Timer called\n");
+//!
+//!         let flag = this.shared.flag.fetch_add(1, ordering::Full);
+//!         this.shared.cond.complete_all();
+//!
+//!         if flag == 4 {
+//!             HrTimerRestart::NoRestart
+//!         } else {
+//!             HrTimerRestart::Restart
+//!         }
+//!     }
+//! }
+//!
+//! impl_has_hr_timer! {
+//!     impl HasHrTimer<Self> for IntrusiveHrTimer {
+//!         mode: RelativeMode<Monotonic>, field: self.timer
+//!     }
+//! }
+//!
+//! stack_try_pin_init!( let has_timer =? IntrusiveHrTimer::new() );
+//! let shared = has_timer.shared.clone();
+//!
+//! has_timer.as_mut().start_scoped(Delta::from_micros(200), || {
+//!     while shared.flag.load(ordering::Relaxed) != 5 {
+//!         shared.cond.wait_for_completion();
+//!     }
+//! });
+//!
+//! pr_info!("Counted to 5\n");
+//! # Ok::<(), kernel::error::Error>(())
+//! ```
+//!
+//! [`Arc`]: kernel::sync::Arc
 
 use super::{ClockSource, Delta, Instant};
 use crate::{prelude::*, types::Opaque};

---
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
change-id: 20251215-hrtimer-examples-v6-19-rc1-2658ce9bb5d0

Best regards,
-- 
Andreas Hindborg <a.hindborg@kernel.org>
Re: [PATCH v3] hrtimer: add usage examples to documentation
Posted by Miguel Ojeda 1 month, 3 weeks ago
On Fri, Feb 20, 2026 at 9:12 AM Andreas Hindborg <a.hindborg@kernel.org> wrote:
>
> +//!     prelude::*,

The prelude should already be there in examples.

> +//!     sync::{
> +//!         atomic::{ordering, Atomic},
> +//!         completion::Completion,
> +//!         Arc,
> +//!     },
> +//!     time::{
> +//!         hrtimer::{
> +//!             RelativeMode, HrTimer, HrTimerCallback, HrTimerPointer,
> +//!             HrTimerRestart, HrTimerCallbackContext
> +//!         },
> +//!         Delta, Monotonic,
> +//!     },
> +//! };

This uses a mixture of the vertical style and the horizontal one -- I
guess you did it to save on lines, but it looks strange now that we
have a style for imports.

I guess you thought about it, but I wonder if the examples could be
merged to some degree to make them more readable...

Cheers,
Miguel
Re: [PATCH v3] hrtimer: add usage examples to documentation
Posted by Andreas Hindborg 1 month, 3 weeks ago
Miguel Ojeda <miguel.ojeda.sandonis@gmail.com> writes:

> On Fri, Feb 20, 2026 at 9:12 AM Andreas Hindborg <a.hindborg@kernel.org> wrote:
>>
>> +//!     prelude::*,
>
> The prelude should already be there in examples.
>
>> +//!     sync::{
>> +//!         atomic::{ordering, Atomic},
>> +//!         completion::Completion,
>> +//!         Arc,
>> +//!     },
>> +//!     time::{
>> +//!         hrtimer::{
>> +//!             RelativeMode, HrTimer, HrTimerCallback, HrTimerPointer,
>> +//!             HrTimerRestart, HrTimerCallbackContext
>> +//!         },
>> +//!         Delta, Monotonic,
>> +//!     },
>> +//! };
>
> This uses a mixture of the vertical style and the horizontal one -- I
> guess you did it to save on lines, but it looks strange now that we
> have a style for imports.

It uses random line breaks to make check_patch.pl not yell at me. I
guess I could copy them somewhere else, do the formatting and copy them
back. Not really a workflow I care for though.

> I guess you thought about it, but I wonder if the examples could be
> merged to some degree to make them more readable...

I don't think they would read better by combining them.

Best regards,
Andreas Hindborg
Re: [PATCH v3] hrtimer: add usage examples to documentation
Posted by Andreas Hindborg 1 month, 3 weeks ago
Andreas Hindborg <a.hindborg@kernel.org> writes:

> Miguel Ojeda <miguel.ojeda.sandonis@gmail.com> writes:
>
>> On Fri, Feb 20, 2026 at 9:12 AM Andreas Hindborg <a.hindborg@kernel.org> wrote:
>>>
>>> +//!     prelude::*,
>>
>> The prelude should already be there in examples.
>>
>>> +//!     sync::{
>>> +//!         atomic::{ordering, Atomic},
>>> +//!         completion::Completion,
>>> +//!         Arc,
>>> +//!     },
>>> +//!     time::{
>>> +//!         hrtimer::{
>>> +//!             RelativeMode, HrTimer, HrTimerCallback, HrTimerPointer,
>>> +//!             HrTimerRestart, HrTimerCallbackContext
>>> +//!         },
>>> +//!         Delta, Monotonic,
>>> +//!     },
>>> +//! };
>>
>> This uses a mixture of the vertical style and the horizontal one -- I
>> guess you did it to save on lines, but it looks strange now that we
>> have a style for imports.
>
> It uses random line breaks to make check_patch.pl not yell at me. I
> guess I could copy them somewhere else, do the formatting and copy them
> back. Not really a workflow I care for though.

So, after copying these use statements elsewhere to format them, I was
rereading your message and I see that what you actually write is that
maybe we should be using the vertical style for imports in examples.

The examples would be nothing but a wall of use statements. Do we
really want that? I know it is the style we picked for the kernel in
general, but I don't think it should necessarily apply to the examples.


Best regards,
Andreas Hindborg
Re: [PATCH v3] hrtimer: add usage examples to documentation
Posted by Miguel Ojeda 1 month, 3 weeks ago
On Mon, Feb 23, 2026 at 4:29 PM Andreas Hindborg <a.hindborg@kernel.org> wrote:
>
> So, after copying these use statements elsewhere to format them, I was
> rereading your message and I see that what you actually write is that
> maybe we should be using the vertical style for imports in examples.
>
> The examples would be nothing but a wall of use statements. Do we
> really want that? I know it is the style we picked for the kernel in
> general, but I don't think it should necessarily apply to the examples.

That is why I asked if we could perhaps merge two pairs of examples :)
i.e. to reduce the "duplicated" boilerplate from the imports, and
perhaps a couple of the items/types that are the same too.

Either that, or you may want to hide them (but I am considering that
we may want to just never hide them (or always doing so) and thus
avoid the discussions that keep coming up on that).

As for using a different style for examples, I can see we could save a
few lines per example, but we would have to remember a different
convention and we would increase the risk of conflicts there (though I
reckon there may be not many conflicts there unlike the module
imports).

Cheers,
Miguel
Re: [PATCH v3] hrtimer: add usage examples to documentation
Posted by Andreas Hindborg 1 month, 3 weeks ago
"Miguel Ojeda" <miguel.ojeda.sandonis@gmail.com> writes:

> On Mon, Feb 23, 2026 at 4:29 PM Andreas Hindborg <a.hindborg@kernel.org> wrote:
>>
>> So, after copying these use statements elsewhere to format them, I was
>> rereading your message and I see that what you actually write is that
>> maybe we should be using the vertical style for imports in examples.
>>
>> The examples would be nothing but a wall of use statements. Do we
>> really want that? I know it is the style we picked for the kernel in
>> general, but I don't think it should necessarily apply to the examples.
>
> That is why I asked if we could perhaps merge two pairs of examples :)
> i.e. to reduce the "duplicated" boilerplate from the imports, and
> perhaps a couple of the items/types that are the same too.
>
> Either that, or you may want to hide them (but I am considering that
> we may want to just never hide them (or always doing so) and thus
> avoid the discussions that keep coming up on that).
>
> As for using a different style for examples, I can see we could save a
> few lines per example, but we would have to remember a different
> convention and we would increase the risk of conflicts there (though I
> reckon there may be not many conflicts there unlike the module
> imports).

I think I'll await broader consensus before shipping another version of
this patch. My 2c is that the imports take away form the actual example
code. I'd rather not have them.

If we are going to keep the imports visible in the examples, I would
prefer to fold the imports, so they take less space. I realize this is
not consistent with the general style we adopted, but I don't think that
is important. These are just examples to help understand an API. They
are not going to be subject of merge conflicts at a regular basis.

If we hide the imports, we might as well go for consistency with the
style we adopted.

Best regards,
Andreas Hindborg