mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Frederic Weisbecker <frederic@kernel.org>
To: Andreas Hindborg <a.hindborg@kernel.org>
Cc: "Miguel Ojeda" <ojeda@kernel.org>,
	"Anna-Maria Behnsen" <anna-maria@linutronix.de>,
	"Thomas Gleixner" <tglx@linutronix.de>,
	"Danilo Krummrich" <dakr@kernel.org>,
	"Alex Gaynor" <alex.gaynor@gmail.com>,
	"Boqun Feng" <boqun.feng@gmail.com>,
	"Gary Guo" <gary@garyguo.net>,
	"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
	"Benno Lossin" <benno.lossin@proton.me>,
	"Alice Ryhl" <aliceryhl@google.com>,
	"Trevor Gross" <tmgross@umich.edu>,
	"Lyude Paul" <lyude@redhat.com>,
	"Guangbo Cui" <2407018371@qq.com>,
	"Dirk Behme" <dirk.behme@gmail.com>,
	"Daniel Almeida" <daniel.almeida@collabora.com>,
	rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v5 02/14] rust: hrtimer: introduce hrtimer support
Date: Tue, 17 Dec 2024 16:56:54 +0100	[thread overview]
Message-ID: <Z2GfRgwIA0-zQmXc@localhost.localdomain> (raw)
In-Reply-To: <20241217-hrtimer-v3-v6-12-rc2-v5-2-b34c20ac2cb7@kernel.org>

Le Tue, Dec 17, 2024 at 04:17:33PM +0100, Andreas Hindborg a écrit :
> This patch adds support for intrusive use of the hrtimer system. For now,
> only one timer can be embedded in a Rust struct.
> 
> The hrtimer Rust API is based on the intrusive style pattern introduced by
> the Rust workqueue API.
> 
> Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
> ---
>  rust/kernel/time.rs         |   2 +
>  rust/kernel/time/hrtimer.rs | 296 ++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 298 insertions(+)
> 
> diff --git a/rust/kernel/time.rs b/rust/kernel/time.rs
> index f59e0fea79d3acfddd922f601f569353609aeec1..51c3532eee0184495ed5b7d717860c9980ff2a43 100644
> --- a/rust/kernel/time.rs
> +++ b/rust/kernel/time.rs
> @@ -10,6 +10,8 @@
>  
>  use core::convert::Into;
>  
> +pub mod hrtimer;
> +
>  /// The number of nanoseconds per millisecond.
>  pub const NSEC_PER_MSEC: i64 = bindings::NSEC_PER_MSEC as i64;
>  
> diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs
> new file mode 100644
> index 0000000000000000000000000000000000000000..b09bdb8bc2037bf116a9a87b16271f4045f53aa9
> --- /dev/null
> +++ b/rust/kernel/time/hrtimer.rs
> @@ -0,0 +1,296 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +//! Intrusive high resolution timers.
> +//!
> +//! Allows running timer callbacks without doing allocations at the time of
> +//! starting the timer. For now, only one timer per type is allowed.
> +//!
> +//! # Vocabulary
> +//!
> +//! A timer is initialized in the **stopped** state. A stopped timer can be
> +//! **started** with an **expiry** time. After the timer is started, it is
> +//! **running**. When the timer **expires**, the timer handler is executed.
> +//! After the handler has executed, the timer may be **restarted** or
> +//! **stopped**. A running timer can be **cancelled** before it's handler is
> +//! executed. A timer that is cancelled enters the **stopped** state.
> +//!
> +//! States:
> +//!
> +//! * Stopped
> +//! * Running
> +//!
> +//! Operations:
> +//!
> +//! * Start
> +//! * Cancel
> +//! * Stop
> +//! * Restart
> +//!
> +//! Events:
> +//!
> +//! * Expire
> +
> +use crate::{init::PinInit, prelude::*, time::Ktime, types::Opaque};
> +use core::marker::PhantomData;
> +
> +/// A timer backed by a C `struct hrtimer`.
> +///
> +/// # Invariants
> +///
> +/// * `self.timer` is initialized by `bindings::hrtimer_setup`.
> +#[pin_data]
> +#[repr(C)]
> +pub struct Timer<U> {

I seem to remember we had a debate on that. Why not call that Hrtimer?
Timer is a bit too generic for a name. I suspect you'll need to introduce
jiffies based timer bindings in the future as well and then some confusion
may arise.

> +    #[pin]
> +    timer: Opaque<bindings::hrtimer>,
> +    _t: PhantomData<U>,
> +}
> +
> +// SAFETY: A `Timer` can be moved to other threads and used/dropped from there.
> +unsafe impl<U> Send for Timer<U> {}
> +
> +// SAFETY: Timer operations are locked on C side, so it is safe to operate on a
> +// timer from multiple threads
> +unsafe impl<U> Sync for Timer<U> {}
> +
> +impl<T> Timer<T> {
> +    /// Return an initializer for a new timer instance.
> +    pub fn new() -> impl PinInit<Self>
> +    where
> +        T: TimerCallback,
> +    {
> +        pin_init!(Self {
> +            // INVARIANTS: We initialize `timer` with `hrtimer_setup` below.
> +            timer <- Opaque::ffi_init(move |place: *mut bindings::hrtimer| {
> +                // SAFETY: By design of `pin_init!`, `place` is a pointer live
> +                // allocation. hrtimer_setup will initialize `place` and does
> +                // not require `place` to be initialized prior to the call.
> +                unsafe {
> +                    bindings::hrtimer_setup(
> +                        place,
> +                        Some(T::CallbackTarget::run),
> +                        bindings::CLOCK_MONOTONIC as i32,
> +                        bindings::hrtimer_mode_HRTIMER_MODE_REL,

Always relative?

> +                    );
> +                }
> +            }),
> +            _t: PhantomData,
> +        })
> +    }
> +
> +    /// Get a pointer to the contained `bindings::hrtimer`.
> +    ///
> +    /// # Safety
> +    ///
> +    /// `ptr` must point to a live allocation of at least the size of `Self`.
> +    unsafe fn raw_get(ptr: *const Self) -> *mut bindings::hrtimer {
> +        // SAFETY: The field projection to `timer` does not go out of bounds,
> +        // because the caller of this function promises that `ptr` points to an
> +        // allocation of at least the size of `Self`.
> +        unsafe { Opaque::raw_get(core::ptr::addr_of!((*ptr).timer)) }
> +    }
> +
> +    /// Cancel an initialized and potentially running timer.
> +    ///
> +    /// If the timer handler is running, this will block until the handler is
> +    /// finished.
> +    ///
> +    /// # Safety
> +    ///
> +    /// `self_ptr` must point to a valid `Self`.
> +    #[allow(dead_code)]
> +    pub(crate) unsafe fn raw_cancel(self_ptr: *const Self) -> bool {
> +        // SAFETY: timer_ptr points to an allocation of at least `Timer` size.
> +        let c_timer_ptr = unsafe { Timer::raw_get(self_ptr) };
> +
> +        // If handler is running, this will wait for handler to finish before
> +        // returning.
> +        // SAFETY: `c_timer_ptr` is initialized and valid. Synchronization is
> +        // handled on C side.
> +        unsafe { bindings::hrtimer_cancel(c_timer_ptr) != 0 }
> +    }
> +}
> +
> +/// Implemented by pointer types that point to structs that embed a [`Timer`].
> +///
> +/// Typical implementers would be [`Box<T>`], [`Arc<T>`], [`ARef<T>`] where `T`
> +/// has a field of type `Timer`.
> +///
> +/// Target must be [`Sync`] because timer callbacks happen in another thread of
> +/// execution (hard or soft interrupt context).
> +///
> +/// Starting a timer returns a [`TimerHandle`] that can be used to manipulate
> +/// the timer. Note that it is OK to call the start function repeatedly, and
> +/// that more than one [`TimerHandle`] associated with a `TimerPointer` may
> +/// exist. A timer can be manipulated through any of the handles, and a handle
> +/// may represent a cancelled timer.
> +///
> +/// [`Box<T>`]: Box
> +/// [`Arc<T>`]: crate::sync::Arc
> +/// [`ARef<T>`]: crate::types::ARef
> +pub trait TimerPointer: Sync + Sized {
> +    /// A handle representing a running timer.
> +    ///
> +    /// If the timer is running or if the timer callback is executing when the
> +    /// handle is dropped, the drop method of `TimerHandle` should not return
> +    /// until the timer is stopped and the callback has completed.
> +    ///
> +    /// Note: It must be safe to leak the handle.
> +    type TimerHandle: TimerHandle;
> +
> +    /// 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;
> +}
> +
> +/// Implemented by [`TimerPointer`] implementers to give the C timer callback a
> +/// function to call.
> +// This is split from `TimerPointer` to make it easier to specify trait bounds.
> +pub trait RawTimerCallback {

RawHrtimerCallback ?

> +    /// Callback to be called from C when timer fires.
> +    ///
> +    /// # Safety
> +    ///
> +    /// Only to be called by C code in `hrtimer` subsystem. `ptr` must point to
> +    /// the `bindings::hrtimer` structure that was used to start the timer.
> +    unsafe extern "C" fn run(ptr: *mut bindings::hrtimer) -> bindings::hrtimer_restart;
> +}
> +
> +/// Implemented by structs that can the target of a timer callback.
> +pub trait TimerCallback {

HrtimerCallback ? etc...

Thanks.

  reply	other threads:[~2024-12-17 15:56 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-12-17 15:17 [PATCH v5 00/14] hrtimer Rust API Andreas Hindborg
2024-12-17 15:17 ` [PATCH v5 01/14] rust: time: Add Ktime::from_ns() Andreas Hindborg
2024-12-17 15:17 ` [PATCH v5 02/14] rust: hrtimer: introduce hrtimer support Andreas Hindborg
2024-12-17 15:56   ` Frederic Weisbecker [this message]
2024-12-18  9:53     ` Andreas Hindborg
2024-12-17 15:17 ` [PATCH v5 03/14] rust: sync: add `Arc::as_ptr` Andreas Hindborg
2024-12-17 15:17 ` [PATCH v5 04/14] rust: hrtimer: implement `TimerPointer` for `Arc` Andreas Hindborg
2024-12-17 15:17 ` [PATCH v5 05/14] rust: hrtimer: allow timer restart from timer handler Andreas Hindborg
     [not found]   ` <H7fH3H6SrsqtETrWgmThmdGUchRyUZh6hQzk4lVMjEOiY_VfUAHbzIGuWZda0aPObsMSxSfyDxhAC9QSTmiPBw==@protonmail.internalid>
     [not found]     ` <tencent_74DA73ADC948EF2F933592E880CC09D35B09@qq.com>
2025-01-09 13:20       ` Andreas Hindborg
2024-12-17 15:17 ` [PATCH v5 06/14] rust: hrtimer: add `UnsafeTimerPointer` Andreas Hindborg
2024-12-17 15:17 ` [PATCH v5 07/14] rust: hrtimer: add `hrtimer::ScopedTimerPointer` Andreas Hindborg
2024-12-17 15:17 ` [PATCH v5 08/14] rust: hrtimer: implement `UnsafeTimerPointer` for `Pin<&T>` Andreas Hindborg
2024-12-17 15:17 ` [PATCH v5 09/14] rust: hrtimer: implement `UnsafeTimerPointer` for `Pin<&mut T>` Andreas Hindborg
2024-12-17 15:17 ` [PATCH v5 10/14] rust: alloc: add `Box::into_pin` Andreas Hindborg
2024-12-17 15:17 ` [PATCH v5 11/14] rust: hrtimer: implement `TimerPointer` for `Pin<Box<T>>` Andreas Hindborg
2024-12-17 15:17 ` [PATCH v5 12/14] rust: hrtimer: add `TimerMode` Andreas Hindborg
2024-12-17 15:17 ` [PATCH v5 13/14] rust: hrtimer: add clocksource selection through `ClockSource` Andreas Hindborg
2024-12-17 15:17 ` [PATCH v5 14/14] rust: hrtimer: add maintainer entry 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=Z2GfRgwIA0-zQmXc@localhost.localdomain \
    --to=frederic@kernel.org \
    --cc=2407018371@qq.com \
    --cc=a.hindborg@kernel.org \
    --cc=alex.gaynor@gmail.com \
    --cc=aliceryhl@google.com \
    --cc=anna-maria@linutronix.de \
    --cc=benno.lossin@proton.me \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun.feng@gmail.com \
    --cc=dakr@kernel.org \
    --cc=daniel.almeida@collabora.com \
    --cc=dirk.behme@gmail.com \
    --cc=gary@garyguo.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lyude@redhat.com \
    --cc=ojeda@kernel.org \
    --cc=rust-for-linux@vger.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®