From: Alice Ryhl <aliceryhl@google.com>
To: Andreas Hindborg <a.hindborg@kernel.org>
Cc: "Boqun Feng" <boqun.feng@gmail.com>,
"FUJITA Tomonori" <fujita.tomonori@gmail.com>,
"Frederic Weisbecker" <frederic@kernel.org>,
"Lyude Paul" <lyude@redhat.com>,
"Thomas Gleixner" <tglx@linutronix.de>,
"Anna-Maria Behnsen" <anna-maria@linutronix.de>,
"John Stultz" <jstultz@google.com>,
"Stephen Boyd" <sboyd@kernel.org>,
"Miguel Ojeda" <ojeda@kernel.org>, "Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <lossin@kernel.org>,
"Trevor Gross" <tmgross@umich.edu>,
"Danilo Krummrich" <dakr@kernel.org>,
rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org,
"Daniel Almeida" <daniel.almeida@collabora.com>
Subject: Re: [PATCH v2] hrtimer: add usage examples to documentation
Date: Thu, 19 Feb 2026 12:31:00 +0000 [thread overview]
Message-ID: <aZcChDe_Y3eyLuYS@google.com> (raw)
In-Reply-To: <20260219-hrtimer-examples-v6-19-rc1-v2-1-810cc06ca9f6@kernel.org>
On Thu, Feb 19, 2026 at 12:57:45PM +0100, Andreas Hindborg wrote:
> 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>
> Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
> ---
> 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..2d7f1131a8131 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,
> +//! # },
> +//! # };
> +//!
Either do not hide the imports, or remove this empty newline.
> +//! #[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,
> +//! # },
> +//! # };
> +//!
Ditto.
> +//! #[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;
> +//!
Ditto.
> +//! #[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;
> +//!
Ditto.
> +//! #[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>
>
>
next prev parent reply other threads:[~2026-02-19 12:31 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-19 11:57 [PATCH v2] hrtimer: add usage examples to documentation Andreas Hindborg
2026-02-19 12:31 ` Alice Ryhl [this message]
2026-02-19 13:35 ` Andreas Hindborg
2026-02-19 13:39 ` Alice Ryhl
2026-03-23 11:07 ` Andreas Hindborg
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aZcChDe_Y3eyLuYS@google.com \
--to=aliceryhl@google.com \
--cc=a.hindborg@kernel.org \
--cc=anna-maria@linutronix.de \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=dakr@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=frederic@kernel.org \
--cc=fujita.tomonori@gmail.com \
--cc=gary@garyguo.net \
--cc=jstultz@google.com \
--cc=linux-kernel@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=lyude@redhat.com \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=sboyd@kernel.org \
--cc=tglx@linutronix.de \
--cc=tmgross@umich.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.