* [PATCH v5 01/14] rust: time: Add Ktime::from_ns()
2024-12-17 15:17 [PATCH v5 00/14] hrtimer Rust API Andreas Hindborg
@ 2024-12-17 15:17 ` Andreas Hindborg
2024-12-17 15:17 ` [PATCH v5 02/14] rust: hrtimer: introduce hrtimer support Andreas Hindborg
` (12 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: Andreas Hindborg @ 2024-12-17 15:17 UTC (permalink / raw)
To: Miguel Ojeda, Anna-Maria Behnsen, Frederic Weisbecker,
Thomas Gleixner, Danilo Krummrich
Cc: Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Alice Ryhl, Trevor Gross, Lyude Paul, Guangbo Cui,
Dirk Behme, Daniel Almeida, rust-for-linux, linux-kernel,
Andreas Hindborg
From: Lyude Paul <lyude@redhat.com>
A simple function to turn the provided value in nanoseconds into a Ktime
value. We allow any type which implements Into<bindings::ktime_t>, which
resolves to Into<i64>.
This is useful for some of the older DRM APIs that never got moved to Ktime
Signed-off-by: Lyude Paul <lyude@redhat.com>
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
rust/kernel/time.rs | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/rust/kernel/time.rs b/rust/kernel/time.rs
index 379c0f5772e575c9ceacb9c85255b13501db8f30..f59e0fea79d3acfddd922f601f569353609aeec1 100644
--- a/rust/kernel/time.rs
+++ b/rust/kernel/time.rs
@@ -8,6 +8,8 @@
//! C header: [`include/linux/jiffies.h`](srctree/include/linux/jiffies.h).
//! C header: [`include/linux/ktime.h`](srctree/include/linux/ktime.h).
+use core::convert::Into;
+
/// The number of nanoseconds per millisecond.
pub const NSEC_PER_MSEC: i64 = bindings::NSEC_PER_MSEC as i64;
@@ -63,6 +65,12 @@ pub fn to_ns(self) -> i64 {
pub fn to_ms(self) -> i64 {
self.divns_constant::<NSEC_PER_MSEC>()
}
+
+ /// Creates a new Ktime from the given duration in nanoseconds
+ #[inline]
+ pub fn from_ns(ns: impl Into<bindings::ktime_t>) -> Self {
+ Self { inner: ns.into() }
+ }
}
/// Returns the number of milliseconds between two ktimes.
--
2.47.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v5 02/14] rust: hrtimer: introduce hrtimer support
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 ` Andreas Hindborg
2024-12-17 15:56 ` Frederic Weisbecker
2024-12-17 15:17 ` [PATCH v5 03/14] rust: sync: add `Arc::as_ptr` Andreas Hindborg
` (11 subsequent siblings)
13 siblings, 1 reply; 18+ messages in thread
From: Andreas Hindborg @ 2024-12-17 15:17 UTC (permalink / raw)
To: Miguel Ojeda, Anna-Maria Behnsen, Frederic Weisbecker,
Thomas Gleixner, Danilo Krummrich
Cc: Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Alice Ryhl, Trevor Gross, Lyude Paul, Guangbo Cui,
Dirk Behme, Daniel Almeida, rust-for-linux, linux-kernel,
Andreas Hindborg
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> {
+ #[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,
+ );
+ }
+ }),
+ _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 {
+ /// 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 {
+ /// The type that was used for starting the timer.
+ type CallbackTarget<'a>: RawTimerCallback;
+
+ /// This type is passed to the timer callback function. It may be a borrow
+ /// of [`Self::CallbackTarget`], or it may be `Self::CallbackTarget` if the
+ /// implementation can guarantee exclusive access to the target during timer
+ /// handler execution.
+ type CallbackTargetParameter<'a>;
+
+ /// Called by the timer logic when the timer fires.
+ fn run(this: Self::CallbackTargetParameter<'_>)
+ where
+ Self: Sized;
+}
+
+/// A handle representing a potentially running timer.
+///
+/// More than one handle representing the same timer might exist.
+///
+/// # Safety
+///
+/// When dropped, the timer represented by this handle must be cancelled, if it
+/// is running. If the timer handler is running when the handle is dropped, the
+/// drop method must wait for the handler to finish before returning.
+pub unsafe trait TimerHandle {
+ /// Cancel the timer, if it is running. If the timer handler is running, block
+ /// till the handler has finished.
+ fn cancel(&mut self) -> bool;
+}
+
+/// Implemented by structs that contain timer nodes.
+///
+/// Clients of the timer API would usually safely implement this trait by using
+/// the [`impl_has_timer`] macro.
+///
+/// # Safety
+///
+/// Implementers of this trait must ensure that the implementer has a [`Timer`]
+/// field at the offset specified by `OFFSET` and that all trait methods are
+/// implemented according to their documentation.
+///
+/// [`impl_has_timer`]: crate::impl_has_timer
+pub unsafe trait HasTimer<U> {
+ /// Offset of the [`Timer`] field within `Self`
+ const OFFSET: usize;
+
+ /// Return a pointer to the [`Timer`] within `Self`.
+ ///
+ /// # Safety
+ ///
+ /// `ptr` must point to a valid struct of type `Self`.
+ unsafe fn raw_get_timer(ptr: *const Self) -> *const Timer<U> {
+ // SAFETY: By the safety requirement of this trait, the trait
+ // implementor will have a `Timer` field at the specified offset.
+ unsafe { ptr.cast::<u8>().add(Self::OFFSET).cast::<Timer<U>>() }
+ }
+
+ /// Return a pointer to the struct that is embedding the [`Timer`] pointed
+ /// to by `ptr`.
+ ///
+ /// # Safety
+ ///
+ /// `ptr` must point to a [`Timer<U>`] field in a struct of type `Self`.
+ unsafe fn timer_container_of(ptr: *mut Timer<U>) -> *mut Self
+ where
+ Self: Sized,
+ {
+ // SAFETY: By the safety requirement of this function and the `HasTimer`
+ // trait, the following expression will yield a pointer to the `Self`
+ // containing the timer addressed by `ptr`.
+ unsafe { ptr.cast::<u8>().sub(Self::OFFSET).cast::<Self>() }
+ }
+
+ /// Get pointer to embedded `bindings::hrtimer` struct.
+ ///
+ /// # Safety
+ ///
+ /// `self_ptr` must point to a valid `Self`.
+ unsafe fn c_timer_ptr(self_ptr: *const Self) -> *const bindings::hrtimer {
+ // SAFETY: `self_ptr` is a valid pointer to a `Self`.
+ let timer_ptr = unsafe { Self::raw_get_timer(self_ptr) };
+
+ // SAFETY: timer_ptr points to an allocation of at least `Timer` size.
+ unsafe { Timer::raw_get(timer_ptr) }
+ }
+
+ /// Start the timer contained in the `Self` pointed to by `self_ptr`. If
+ /// it is already running it is removed and inserted.
+ ///
+ /// # Safety
+ ///
+ /// `self_ptr` must point to a valid `Self`.
+ unsafe fn start(self_ptr: *const Self, expires: Ktime) {
+ // SAFETY: By function safety requirement, `self_ptr`is a valid `Self`.
+ unsafe {
+ bindings::hrtimer_start_range_ns(
+ Self::c_timer_ptr(self_ptr).cast_mut(),
+ expires.to_ns(),
+ 0,
+ bindings::hrtimer_mode_HRTIMER_MODE_REL,
+ );
+ }
+ }
+}
+
+/// Use to implement the [`HasTimer<T>`] trait.
+///
+/// See [`module`] documentation for an example.
+///
+/// [`module`]: crate::time::hrtimer
+#[macro_export]
+macro_rules! impl_has_timer {
+ (
+ impl$({$($generics:tt)*})?
+ HasTimer<$timer_type:ty>
+ for $self:ty
+ { 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::HasTimer<$timer_type> for $self {
+ const OFFSET: usize = ::core::mem::offset_of!(Self, $field) as usize;
+
+ #[inline]
+ unsafe fn raw_get_timer(ptr: *const Self) ->
+ *const $crate::time::hrtimer::Timer<$timer_type>
+ {
+ // SAFETY: The caller promises that the pointer is not dangling.
+ unsafe {
+ ::core::ptr::addr_of!((*ptr).$field)
+ }
+ }
+ }
+ }
+}
--
2.47.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH v5 02/14] rust: hrtimer: introduce hrtimer support
2024-12-17 15:17 ` [PATCH v5 02/14] rust: hrtimer: introduce hrtimer support Andreas Hindborg
@ 2024-12-17 15:56 ` Frederic Weisbecker
2024-12-18 9:53 ` Andreas Hindborg
0 siblings, 1 reply; 18+ messages in thread
From: Frederic Weisbecker @ 2024-12-17 15:56 UTC (permalink / raw)
To: Andreas Hindborg
Cc: Miguel Ojeda, Anna-Maria Behnsen, Thomas Gleixner,
Danilo Krummrich, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Alice Ryhl, Trevor Gross,
Lyude Paul, Guangbo Cui, Dirk Behme, Daniel Almeida,
rust-for-linux, linux-kernel
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.
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v5 02/14] rust: hrtimer: introduce hrtimer support
2024-12-17 15:56 ` Frederic Weisbecker
@ 2024-12-18 9:53 ` Andreas Hindborg
0 siblings, 0 replies; 18+ messages in thread
From: Andreas Hindborg @ 2024-12-18 9:53 UTC (permalink / raw)
To: Frederic Weisbecker
Cc: Miguel Ojeda, Anna-Maria Behnsen, Thomas Gleixner,
Danilo Krummrich, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Alice Ryhl, Trevor Gross,
Lyude Paul, Guangbo Cui, Dirk Behme, Daniel Almeida,
rust-for-linux, linux-kernel
"Frederic Weisbecker" <frederic@kernel.org> writes:
> 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.
Yes, let's rename it. Good call.
>
>> + #[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?
`TimerMode` is introduced in patch 12.
>
>> + );
>> + }
>> + }),
>> + _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 ?
Yes!
>
>> + /// 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...
Will do a rename pass.
Best regards,
Andreas Hindborg
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v5 03/14] rust: sync: add `Arc::as_ptr`
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:17 ` Andreas Hindborg
2024-12-17 15:17 ` [PATCH v5 04/14] rust: hrtimer: implement `TimerPointer` for `Arc` Andreas Hindborg
` (10 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: Andreas Hindborg @ 2024-12-17 15:17 UTC (permalink / raw)
To: Miguel Ojeda, Anna-Maria Behnsen, Frederic Weisbecker,
Thomas Gleixner, Danilo Krummrich
Cc: Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Alice Ryhl, Trevor Gross, Lyude Paul, Guangbo Cui,
Dirk Behme, Daniel Almeida, rust-for-linux, linux-kernel,
Andreas Hindborg
Add a method to get a pointer to the data contained in an `Arc`.
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
rust/kernel/sync/arc.rs | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs
index fa4509406ee909ca0677b78d5ece966089ce6366..3d6111ddb007285b26eca2177a412033f4ac5dcb 100644
--- a/rust/kernel/sync/arc.rs
+++ b/rust/kernel/sync/arc.rs
@@ -233,6 +233,15 @@ pub fn into_raw(self) -> *const T {
unsafe { core::ptr::addr_of!((*ptr).data) }
}
+ /// Return a raw pointer to the data in this arc.
+ pub fn as_ptr(this: &Self) -> *const T {
+ let ptr = this.ptr.as_ptr();
+
+ // SAFETY: As `ptr` points to a valid allocation of type `ArcInner`,
+ // field projection to `data`is within bounds of the allocation.
+ unsafe { core::ptr::addr_of!((*ptr).data) }
+ }
+
/// Recreates an [`Arc`] instance previously deconstructed via [`Arc::into_raw`].
///
/// # Safety
@@ -508,11 +517,11 @@ unsafe fn new(inner: NonNull<ArcInner<T>>) -> Self {
}
/// Creates an [`ArcBorrow`] to an [`Arc`] that has previously been deconstructed with
- /// [`Arc::into_raw`].
+ /// [`Arc::into_raw`] or [`Arc::as_ptr`].
///
/// # Safety
///
- /// * The provided pointer must originate from a call to [`Arc::into_raw`].
+ /// * The provided pointer must originate from a call to [`Arc::into_raw`] or [`Arc::as_ptr`].
/// * For the duration of the lifetime annotated on this `ArcBorrow`, the reference count must
/// not hit zero.
/// * For the duration of the lifetime annotated on this `ArcBorrow`, there must not be a
--
2.47.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v5 04/14] rust: hrtimer: implement `TimerPointer` for `Arc`
2024-12-17 15:17 [PATCH v5 00/14] hrtimer Rust API Andreas Hindborg
` (2 preceding siblings ...)
2024-12-17 15:17 ` [PATCH v5 03/14] rust: sync: add `Arc::as_ptr` Andreas Hindborg
@ 2024-12-17 15:17 ` Andreas Hindborg
2024-12-17 15:17 ` [PATCH v5 05/14] rust: hrtimer: allow timer restart from timer handler Andreas Hindborg
` (9 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: Andreas Hindborg @ 2024-12-17 15:17 UTC (permalink / raw)
To: Miguel Ojeda, Anna-Maria Behnsen, Frederic Weisbecker,
Thomas Gleixner, Danilo Krummrich
Cc: Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Alice Ryhl, Trevor Gross, Lyude Paul, Guangbo Cui,
Dirk Behme, Daniel Almeida, rust-for-linux, linux-kernel,
Andreas Hindborg
This patch allows the use of intrusive `hrtimer` fields in structs that are
managed by an `Arc`.
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
rust/kernel/time/hrtimer.rs | 3 +-
rust/kernel/time/hrtimer/arc.rs | 89 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 91 insertions(+), 1 deletion(-)
diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs
index b09bdb8bc2037bf116a9a87b16271f4045f53aa9..178e33c1f656d2f834e45b004486f6e5fe1813dd 100644
--- a/rust/kernel/time/hrtimer.rs
+++ b/rust/kernel/time/hrtimer.rs
@@ -98,7 +98,6 @@ unsafe fn raw_get(ptr: *const Self) -> *mut bindings::hrtimer {
/// # 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) };
@@ -294,3 +293,5 @@ unsafe fn raw_get_timer(ptr: *const Self) ->
}
}
}
+
+mod arc;
diff --git a/rust/kernel/time/hrtimer/arc.rs b/rust/kernel/time/hrtimer/arc.rs
new file mode 100644
index 0000000000000000000000000000000000000000..3b256292bc86160a495f7b192b3eda92f2dfcb31
--- /dev/null
+++ b/rust/kernel/time/hrtimer/arc.rs
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0
+
+use super::HasTimer;
+use super::RawTimerCallback;
+use super::Timer;
+use super::TimerCallback;
+use super::TimerHandle;
+use super::TimerPointer;
+use crate::sync::Arc;
+use crate::sync::ArcBorrow;
+use crate::time::Ktime;
+
+/// A handle for an `Arc<HasTimer<U>>` returned by a call to
+/// [`TimerPointer::start`].
+pub struct ArcTimerHandle<U>
+where
+ U: HasTimer<U>,
+{
+ pub(crate) inner: Arc<U>,
+}
+
+// SAFETY: We implement drop below, and we cancel the timer in the drop
+// implementation.
+unsafe impl<U> TimerHandle for ArcTimerHandle<U>
+where
+ U: HasTimer<U>,
+{
+ fn cancel(&mut self) -> bool {
+ let self_ptr = Arc::as_ptr(&self.inner);
+
+ // SAFETY: As we obtained `self_ptr` from a valid reference above, it
+ // must point to a valid `U`.
+ let timer_ptr = unsafe { <U as HasTimer<U>>::raw_get_timer(self_ptr) };
+
+ // SAFETY: As `timer_ptr` points into `U` and `U` is valid, `timer_ptr`
+ // must point to a valid `Timer` instance.
+ unsafe { Timer::<U>::raw_cancel(timer_ptr) }
+ }
+}
+
+impl<U> Drop for ArcTimerHandle<U>
+where
+ U: HasTimer<U>,
+{
+ fn drop(&mut self) {
+ self.cancel();
+ }
+}
+
+impl<U> TimerPointer for Arc<U>
+where
+ U: Send + Sync,
+ U: HasTimer<U>,
+ U: for<'a> TimerCallback<CallbackTarget<'a> = Self>,
+{
+ type TimerHandle = ArcTimerHandle<U>;
+
+ fn start(self, expires: Ktime) -> ArcTimerHandle<U> {
+ // SAFETY: Since we generate the pointer passed to `start` from a
+ // valid reference, it is a valid pointer.
+ unsafe { U::start(Arc::as_ptr(&self), expires) };
+
+ ArcTimerHandle { inner: self }
+ }
+}
+
+impl<U> RawTimerCallback for Arc<U>
+where
+ U: HasTimer<U>,
+ U: for<'a> TimerCallback<CallbackTarget<'a> = Self>,
+ U: for<'a> TimerCallback<CallbackTargetParameter<'a> = ArcBorrow<'a, U>>,
+{
+ unsafe extern "C" fn run(ptr: *mut bindings::hrtimer) -> bindings::hrtimer_restart {
+ // `Timer` is `repr(C)`
+ let timer_ptr = ptr.cast::<super::Timer<U>>();
+
+ // SAFETY: By C API contract `ptr` is the pointer we passed when
+ // queuing the timer, so it is a `Timer<T>` embedded in a `T`.
+ let data_ptr = unsafe { U::timer_container_of(timer_ptr) };
+
+ // SAFETY: `data_ptr` points to the `U` that was used to queue the
+ // timer. This `U` is contained in an `Arc`.
+ let receiver = unsafe { ArcBorrow::from_raw(data_ptr) };
+
+ U::run(receiver);
+
+ bindings::hrtimer_restart_HRTIMER_NORESTART
+ }
+}
--
2.47.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v5 05/14] rust: hrtimer: allow timer restart from timer handler
2024-12-17 15:17 [PATCH v5 00/14] hrtimer Rust API Andreas Hindborg
` (3 preceding siblings ...)
2024-12-17 15:17 ` [PATCH v5 04/14] rust: hrtimer: implement `TimerPointer` for `Arc` Andreas Hindborg
@ 2024-12-17 15:17 ` Andreas Hindborg
[not found] ` <H7fH3H6SrsqtETrWgmThmdGUchRyUZh6hQzk4lVMjEOiY_VfUAHbzIGuWZda0aPObsMSxSfyDxhAC9QSTmiPBw==@protonmail.internalid>
2024-12-17 15:17 ` [PATCH v5 06/14] rust: hrtimer: add `UnsafeTimerPointer` Andreas Hindborg
` (8 subsequent siblings)
13 siblings, 1 reply; 18+ messages in thread
From: Andreas Hindborg @ 2024-12-17 15:17 UTC (permalink / raw)
To: Miguel Ojeda, Anna-Maria Behnsen, Frederic Weisbecker,
Thomas Gleixner, Danilo Krummrich
Cc: Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Alice Ryhl, Trevor Gross, Lyude Paul, Guangbo Cui,
Dirk Behme, Daniel Almeida, rust-for-linux, linux-kernel,
Andreas Hindborg
This patch allows timer handlers to report that they want a timer to be
restarted after the timer handler has finished executing.
Also update the `hrtimer` documentation to showcase the new feature.
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
rust/kernel/time/hrtimer.rs | 37 ++++++++++++++++++++++++++++++++++++-
rust/kernel/time/hrtimer/arc.rs | 4 +---
2 files changed, 37 insertions(+), 4 deletions(-)
diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs
index 178e33c1f656d2f834e45b004486f6e5fe1813dd..38a8251ea6ba4d84dadad009ed540c150bea4775 100644
--- a/rust/kernel/time/hrtimer.rs
+++ b/rust/kernel/time/hrtimer.rs
@@ -167,7 +167,7 @@ pub trait TimerCallback {
type CallbackTargetParameter<'a>;
/// Called by the timer logic when the timer fires.
- fn run(this: Self::CallbackTargetParameter<'_>)
+ fn run(this: Self::CallbackTargetParameter<'_>) -> TimerRestart
where
Self: Sized;
}
@@ -262,6 +262,41 @@ unsafe fn start(self_ptr: *const Self, expires: Ktime) {
}
}
+/// Restart policy for timers.
+pub enum TimerRestart {
+ /// Timer should not be restarted.
+ NoRestart,
+ /// Timer should be restarted.
+ Restart,
+}
+
+impl From<u32> for TimerRestart {
+ fn from(value: u32) -> Self {
+ match value {
+ 0 => Self::NoRestart,
+ _ => Self::Restart,
+ }
+ }
+}
+
+impl From<i32> for TimerRestart {
+ fn from(value: i32) -> Self {
+ match value {
+ 0 => Self::NoRestart,
+ _ => Self::Restart,
+ }
+ }
+}
+
+impl From<TimerRestart> for bindings::hrtimer_restart {
+ fn from(value: TimerRestart) -> Self {
+ match value {
+ TimerRestart::NoRestart => bindings::hrtimer_restart_HRTIMER_NORESTART,
+ TimerRestart::Restart => bindings::hrtimer_restart_HRTIMER_RESTART,
+ }
+ }
+}
+
/// Use to implement the [`HasTimer<T>`] trait.
///
/// See [`module`] documentation for an example.
diff --git a/rust/kernel/time/hrtimer/arc.rs b/rust/kernel/time/hrtimer/arc.rs
index 3b256292bc86160a495f7b192b3eda92f2dfcb31..1711b41ab32aef0c6f5263eab38bc61d6c2a189c 100644
--- a/rust/kernel/time/hrtimer/arc.rs
+++ b/rust/kernel/time/hrtimer/arc.rs
@@ -82,8 +82,6 @@ impl<U> RawTimerCallback for Arc<U>
// timer. This `U` is contained in an `Arc`.
let receiver = unsafe { ArcBorrow::from_raw(data_ptr) };
- U::run(receiver);
-
- bindings::hrtimer_restart_HRTIMER_NORESTART
+ U::run(receiver).into()
}
}
--
2.47.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v5 06/14] rust: hrtimer: add `UnsafeTimerPointer`
2024-12-17 15:17 [PATCH v5 00/14] hrtimer Rust API Andreas Hindborg
` (4 preceding siblings ...)
2024-12-17 15:17 ` [PATCH v5 05/14] rust: hrtimer: allow timer restart from timer handler Andreas Hindborg
@ 2024-12-17 15:17 ` Andreas Hindborg
2024-12-17 15:17 ` [PATCH v5 07/14] rust: hrtimer: add `hrtimer::ScopedTimerPointer` Andreas Hindborg
` (7 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: Andreas Hindborg @ 2024-12-17 15:17 UTC (permalink / raw)
To: Miguel Ojeda, Anna-Maria Behnsen, Frederic Weisbecker,
Thomas Gleixner, Danilo Krummrich
Cc: Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Alice Ryhl, Trevor Gross, Lyude Paul, Guangbo Cui,
Dirk Behme, Daniel Almeida, rust-for-linux, linux-kernel,
Andreas Hindborg
Add a trait to allow unsafely queuing stack allocated timers.
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
rust/kernel/time/hrtimer.rs | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs
index 38a8251ea6ba4d84dadad009ed540c150bea4775..df0f6e720f1644ca31e0b64cd0f05a4a46098ec4 100644
--- a/rust/kernel/time/hrtimer.rs
+++ b/rust/kernel/time/hrtimer.rs
@@ -142,6 +142,39 @@ pub trait TimerPointer: Sync + Sized {
fn start(self, expires: Ktime) -> Self::TimerHandle;
}
+/// Unsafe version of [`TimerPointer`] for situations where leaking the
+/// `TimerHandle` returned by `start` would be unsound. This is the case for
+/// stack allocated timers.
+///
+/// Typical implementers are pinned references such as [`Pin<&T>`].
+///
+/// # Safety
+///
+/// Implementers of this trait must ensure that instances of types implementing
+/// [`UnsafeTimerPointer`] outlives any associated [`TimerPointer::TimerHandle`]
+/// instances.
+///
+/// [`Pin<&T>`]: Box
+pub unsafe trait UnsafeTimerPointer: Sync + Sized {
+ /// A handle representing a running timer.
+ ///
+ /// # Safety
+ ///
+ /// If the timer is running, or if the timer callback is executing when the
+ /// handle is dropped, the drop method of `TimerHandle` must not return
+ /// until the timer is stopped and the callback has completed.
+ type TimerHandle: TimerHandle;
+
+ /// Start the timer after `expires` time units. If the timer was already
+ /// running, it is restarted at the new expiry time.
+ ///
+ /// # Safety
+ ///
+ /// 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;
+}
+
/// 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.
--
2.47.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v5 07/14] rust: hrtimer: add `hrtimer::ScopedTimerPointer`
2024-12-17 15:17 [PATCH v5 00/14] hrtimer Rust API Andreas Hindborg
` (5 preceding siblings ...)
2024-12-17 15:17 ` [PATCH v5 06/14] rust: hrtimer: add `UnsafeTimerPointer` Andreas Hindborg
@ 2024-12-17 15:17 ` Andreas Hindborg
2024-12-17 15:17 ` [PATCH v5 08/14] rust: hrtimer: implement `UnsafeTimerPointer` for `Pin<&T>` Andreas Hindborg
` (6 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: Andreas Hindborg @ 2024-12-17 15:17 UTC (permalink / raw)
To: Miguel Ojeda, Anna-Maria Behnsen, Frederic Weisbecker,
Thomas Gleixner, Danilo Krummrich
Cc: Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Alice Ryhl, Trevor Gross, Lyude Paul, Guangbo Cui,
Dirk Behme, Daniel Almeida, rust-for-linux, linux-kernel,
Andreas Hindborg
Add the trait `ScopedTimerPointer` to allow safe use of stack allocated
timers. Safety is achieved by pinning the stack in place while timers are
running.
Implement the trait for all types that implement `UnsafeTimerPointer`.
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
rust/kernel/time/hrtimer.rs | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs
index df0f6e720f1644ca31e0b64cd0f05a4a46098ec4..6b03eb4b42dbd6447728c42949a2f93d736dc3b0 100644
--- a/rust/kernel/time/hrtimer.rs
+++ b/rust/kernel/time/hrtimer.rs
@@ -175,6 +175,39 @@ pub unsafe trait UnsafeTimerPointer: Sync + Sized {
unsafe fn start(self, expires: Ktime) -> Self::TimerHandle;
}
+/// A trait for stack allocated timers.
+///
+/// # Safety
+///
+/// Implementers must ensure that `start_scoped` does not return until the
+/// timer is dead and the timer handler is not running.
+pub unsafe trait ScopedTimerPointer {
+ /// 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
+ where
+ F: FnOnce() -> T;
+}
+
+// SAFETY: By the safety requirement of `UnsafeTimerPointer`, dropping the
+// handle returned by [`UnsafeTimerPointer::start`] ensures that the timer is
+// killed.
+unsafe impl<U> ScopedTimerPointer for U
+where
+ U: UnsafeTimerPointer,
+{
+ fn start_scoped<T, F>(self, expires: Ktime, f: F) -> T
+ where
+ F: FnOnce() -> T,
+ {
+ // SAFETY: We drop the timer handle below before returning.
+ let handle = unsafe { UnsafeTimerPointer::start(self, expires) };
+ let t = f();
+ drop(handle);
+ t
+ }
+}
+
/// 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.
--
2.47.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v5 08/14] rust: hrtimer: implement `UnsafeTimerPointer` for `Pin<&T>`
2024-12-17 15:17 [PATCH v5 00/14] hrtimer Rust API Andreas Hindborg
` (6 preceding siblings ...)
2024-12-17 15:17 ` [PATCH v5 07/14] rust: hrtimer: add `hrtimer::ScopedTimerPointer` Andreas Hindborg
@ 2024-12-17 15:17 ` Andreas Hindborg
2024-12-17 15:17 ` [PATCH v5 09/14] rust: hrtimer: implement `UnsafeTimerPointer` for `Pin<&mut T>` Andreas Hindborg
` (5 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: Andreas Hindborg @ 2024-12-17 15:17 UTC (permalink / raw)
To: Miguel Ojeda, Anna-Maria Behnsen, Frederic Weisbecker,
Thomas Gleixner, Danilo Krummrich
Cc: Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Alice Ryhl, Trevor Gross, Lyude Paul, Guangbo Cui,
Dirk Behme, Daniel Almeida, rust-for-linux, linux-kernel,
Andreas Hindborg
Allow pinned references to structs that contain a `Timer` node to be
scheduled with the `hrtimer` subsystem.
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
rust/kernel/time/hrtimer.rs | 1 +
rust/kernel/time/hrtimer/pin.rs | 95 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 96 insertions(+)
diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs
index 6b03eb4b42dbd6447728c42949a2f93d736dc3b0..00172cb50ff153ef2b911f5025bdca40b995e825 100644
--- a/rust/kernel/time/hrtimer.rs
+++ b/rust/kernel/time/hrtimer.rs
@@ -396,3 +396,4 @@ unsafe fn raw_get_timer(ptr: *const Self) ->
}
mod arc;
+mod pin;
diff --git a/rust/kernel/time/hrtimer/pin.rs b/rust/kernel/time/hrtimer/pin.rs
new file mode 100644
index 0000000000000000000000000000000000000000..7b251f157b2c196a3bde220b12619ce0c0ecce6c
--- /dev/null
+++ b/rust/kernel/time/hrtimer/pin.rs
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-2.0
+
+use super::HasTimer;
+use super::RawTimerCallback;
+use super::Timer;
+use super::TimerCallback;
+use super::TimerHandle;
+use super::UnsafeTimerPointer;
+use crate::time::Ktime;
+use core::pin::Pin;
+
+/// A handle for a `Pin<&HasTimer>`. When the handle exists, the timer might be
+/// running.
+pub struct PinTimerHandle<'a, U>
+where
+ U: HasTimer<U>,
+{
+ pub(crate) inner: Pin<&'a U>,
+}
+
+// SAFETY: We cancel the timer when the handle is dropped. The implementation of
+// the `cancel` method will block if the timer handler is running.
+unsafe impl<'a, U> TimerHandle for PinTimerHandle<'a, U>
+where
+ U: HasTimer<U>,
+{
+ fn cancel(&mut self) -> bool {
+ let self_ptr: *const U = self.inner.get_ref();
+
+ // SAFETY: As we got `self_ptr` from a reference above, it must point to
+ // a valid `U`.
+ let timer_ptr = unsafe { <U as HasTimer<U>>::raw_get_timer(self_ptr) };
+
+ // SAFETY: As `timer_ptr` is derived from a reference, it must point to
+ // a valid and initialized `Timer`.
+ unsafe { Timer::<U>::raw_cancel(timer_ptr) }
+ }
+}
+
+impl<'a, U> Drop for PinTimerHandle<'a, U>
+where
+ U: HasTimer<U>,
+{
+ fn drop(&mut self) {
+ self.cancel();
+ }
+}
+
+// SAFETY: We capture the lifetime of `Self` when we create a `PinTimerHandle`,
+// so `Self` will outlive the handle.
+unsafe impl<'a, U> UnsafeTimerPointer for Pin<&'a U>
+where
+ U: Send + Sync,
+ U: HasTimer<U>,
+ U: TimerCallback<CallbackTarget<'a> = Self>,
+{
+ type TimerHandle = PinTimerHandle<'a, U>;
+
+ unsafe fn start(self, expires: Ktime) -> Self::TimerHandle {
+ // Cast to pointer
+ let self_ptr: *const U = <Self as core::ops::Deref>::deref(&self);
+
+ // SAFETY: As we derive `self_ptr` from a reference above, it must point
+ // to a valid `U`.
+ unsafe { U::start(self_ptr, expires) };
+
+ PinTimerHandle { inner: self }
+ }
+}
+
+impl<'a, U> RawTimerCallback for Pin<&'a U>
+where
+ U: HasTimer<U>,
+ U: TimerCallback<CallbackTarget<'a> = Self>,
+ U: TimerCallback<CallbackTargetParameter<'a> = Self>,
+{
+ unsafe extern "C" fn run(ptr: *mut bindings::hrtimer) -> bindings::hrtimer_restart {
+ // `Timer` is `repr(C)`
+ let timer_ptr = ptr as *mut Timer<U>;
+
+ // SAFETY: By the safety requirement of this function, `timer_ptr`
+ // points to a `Timer<U>` contained in an `U`.
+ let receiver_ptr = unsafe { U::timer_container_of(timer_ptr) };
+
+ // SAFETY: By the safety requirement of this function, `timer_ptr`
+ // points to a `Timer<U>` contained in an `U`.
+ let receiver_ref = unsafe { &*receiver_ptr };
+
+ // SAFETY: `receiver_ref` only exists as pinned, so it is safe to pin it
+ // here.
+ let receiver_pin = unsafe { Pin::new_unchecked(receiver_ref) };
+
+ U::run(receiver_pin).into()
+ }
+}
--
2.47.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v5 09/14] rust: hrtimer: implement `UnsafeTimerPointer` for `Pin<&mut T>`
2024-12-17 15:17 [PATCH v5 00/14] hrtimer Rust API Andreas Hindborg
` (7 preceding siblings ...)
2024-12-17 15:17 ` [PATCH v5 08/14] rust: hrtimer: implement `UnsafeTimerPointer` for `Pin<&T>` Andreas Hindborg
@ 2024-12-17 15:17 ` Andreas Hindborg
2024-12-17 15:17 ` [PATCH v5 10/14] rust: alloc: add `Box::into_pin` Andreas Hindborg
` (4 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: Andreas Hindborg @ 2024-12-17 15:17 UTC (permalink / raw)
To: Miguel Ojeda, Anna-Maria Behnsen, Frederic Weisbecker,
Thomas Gleixner, Danilo Krummrich
Cc: Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Alice Ryhl, Trevor Gross, Lyude Paul, Guangbo Cui,
Dirk Behme, Daniel Almeida, rust-for-linux, linux-kernel,
Andreas Hindborg
Allow pinned mutable references to structs that contain a `Timer` node to
be scheduled with the `hrtimer` subsystem.
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
rust/kernel/time/hrtimer.rs | 1 +
rust/kernel/time/hrtimer/pin_mut.rs | 97 +++++++++++++++++++++++++++++++++++++
2 files changed, 98 insertions(+)
diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs
index 00172cb50ff153ef2b911f5025bdca40b995e825..c223f1385c723a0b75e7f8184deadbca38872e0a 100644
--- a/rust/kernel/time/hrtimer.rs
+++ b/rust/kernel/time/hrtimer.rs
@@ -397,3 +397,4 @@ unsafe fn raw_get_timer(ptr: *const Self) ->
mod arc;
mod pin;
+mod pin_mut;
diff --git a/rust/kernel/time/hrtimer/pin_mut.rs b/rust/kernel/time/hrtimer/pin_mut.rs
new file mode 100644
index 0000000000000000000000000000000000000000..50ba9109919838aa9b09381000bab4ab8d3a2340
--- /dev/null
+++ b/rust/kernel/time/hrtimer/pin_mut.rs
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0
+
+use super::HasTimer;
+use super::RawTimerCallback;
+use super::Timer;
+use super::TimerCallback;
+use super::TimerHandle;
+use super::UnsafeTimerPointer;
+use crate::time::Ktime;
+use core::pin::Pin;
+
+/// A handle for a `Pin<&mut HasTimer>`. When the handle exists, the timer might
+/// be running.
+pub struct PinMutTimerHandle<'a, U>
+where
+ U: HasTimer<U>,
+{
+ pub(crate) inner: Pin<&'a mut U>,
+}
+
+// SAFETY: We cancel the timer when the handle is dropped. The implementation of
+// the `cancel` method will block if the timer handler is running.
+unsafe impl<'a, U> TimerHandle for PinMutTimerHandle<'a, U>
+where
+ U: HasTimer<U>,
+{
+ fn cancel(&mut self) -> bool {
+ // SAFETY: We are not moving out of `self` or handing out mutable
+ // references to `self`.
+ let self_ptr = unsafe { self.inner.as_mut().get_unchecked_mut() as *mut U };
+
+ // SAFETY: As we got `self_ptr` from a reference above, it must point to
+ // a valid `U`.
+ let timer_ptr = unsafe { <U as HasTimer<U>>::raw_get_timer(self_ptr) };
+
+ // SAFETY: As `timer_ptr` is derived from a reference, it must point to
+ // a valid and initialized `Timer`.
+ unsafe { Timer::<U>::raw_cancel(timer_ptr) }
+ }
+}
+
+impl<'a, U> Drop for PinMutTimerHandle<'a, U>
+where
+ U: HasTimer<U>,
+{
+ fn drop(&mut self) {
+ self.cancel();
+ }
+}
+
+// SAFETY: We capture the lifetime of `Self` when we create a
+// `PinMutTimerHandle`, so `Self` will outlive the handle.
+unsafe impl<'a, U> UnsafeTimerPointer for Pin<&'a mut U>
+where
+ U: Send + Sync,
+ U: HasTimer<U>,
+ U: TimerCallback<CallbackTarget<'a> = Self>,
+{
+ type TimerHandle = PinMutTimerHandle<'a, U>;
+
+ unsafe fn start(self, expires: Ktime) -> Self::TimerHandle {
+ // Cast to pointer
+ let self_ptr: *const U = <Self as core::ops::Deref>::deref(&self);
+
+ // SAFETY: As we derive `self_ptr` from a reference above, it must point
+ // to a valid `U`.
+ unsafe { U::start(self_ptr, expires) };
+
+ PinMutTimerHandle { inner: self }
+ }
+}
+
+impl<'a, U> RawTimerCallback for Pin<&'a mut U>
+where
+ U: HasTimer<U>,
+ U: TimerCallback<CallbackTarget<'a> = Self>,
+ U: TimerCallback<CallbackTargetParameter<'a> = Self>,
+{
+ unsafe extern "C" fn run(ptr: *mut bindings::hrtimer) -> bindings::hrtimer_restart {
+ // `Timer` is `repr(C)`
+ let timer_ptr = ptr as *mut Timer<U>;
+
+ // SAFETY: By the safety requirement of this function, `timer_ptr`
+ // points to a `Timer<U>` contained in an `U`.
+ let receiver_ptr = unsafe { U::timer_container_of(timer_ptr) };
+
+ // SAFETY: By the safety requirement of this function, `timer_ptr`
+ // points to a `Timer<U>` contained in an `U`.
+ let receiver_ref = unsafe { &mut *receiver_ptr };
+
+ // SAFETY: `receiver_ref` only exists as pinned, so it is safe to pin it
+ // here.
+ let receiver_pin = unsafe { Pin::new_unchecked(receiver_ref) };
+
+ U::run(receiver_pin).into()
+ }
+}
--
2.47.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v5 10/14] rust: alloc: add `Box::into_pin`
2024-12-17 15:17 [PATCH v5 00/14] hrtimer Rust API Andreas Hindborg
` (8 preceding siblings ...)
2024-12-17 15:17 ` [PATCH v5 09/14] rust: hrtimer: implement `UnsafeTimerPointer` for `Pin<&mut T>` Andreas Hindborg
@ 2024-12-17 15:17 ` Andreas Hindborg
2024-12-17 15:17 ` [PATCH v5 11/14] rust: hrtimer: implement `TimerPointer` for `Pin<Box<T>>` Andreas Hindborg
` (3 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: Andreas Hindborg @ 2024-12-17 15:17 UTC (permalink / raw)
To: Miguel Ojeda, Anna-Maria Behnsen, Frederic Weisbecker,
Thomas Gleixner, Danilo Krummrich
Cc: Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Alice Ryhl, Trevor Gross, Lyude Paul, Guangbo Cui,
Dirk Behme, Daniel Almeida, rust-for-linux, linux-kernel,
Andreas Hindborg
Add an associated function to convert a `Box<T>` into a `Pin<Box<T>>`.
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
rust/kernel/alloc/kbox.rs | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs
index 9ce414361c2c6dd8eea09b11041f6c307cbc7864..76f29e2ac085e19871f18653cfddf11d2594682c 100644
--- a/rust/kernel/alloc/kbox.rs
+++ b/rust/kernel/alloc/kbox.rs
@@ -245,6 +245,12 @@ pub fn pin(x: T, flags: Flags) -> Result<Pin<Box<T, A>>, AllocError>
Ok(Self::new(x, flags)?.into())
}
+ /// Convert a [`Box<T,A>`] to a [`Pin<Box<T,A>>`]. If `T` does not implement
+ /// [`Unpin`], then `x` will be pinned in memory and can't be moved.
+ pub fn into_pin(boxed: Self) -> Pin<Self> {
+ boxed.into()
+ }
+
/// Forgets the contents (does not run the destructor), but keeps the allocation.
fn forget_contents(this: Self) -> Box<MaybeUninit<T>, A> {
let ptr = Self::into_raw(this);
--
2.47.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v5 11/14] rust: hrtimer: implement `TimerPointer` for `Pin<Box<T>>`
2024-12-17 15:17 [PATCH v5 00/14] hrtimer Rust API Andreas Hindborg
` (9 preceding siblings ...)
2024-12-17 15:17 ` [PATCH v5 10/14] rust: alloc: add `Box::into_pin` Andreas Hindborg
@ 2024-12-17 15:17 ` Andreas Hindborg
2024-12-17 15:17 ` [PATCH v5 12/14] rust: hrtimer: add `TimerMode` Andreas Hindborg
` (2 subsequent siblings)
13 siblings, 0 replies; 18+ messages in thread
From: Andreas Hindborg @ 2024-12-17 15:17 UTC (permalink / raw)
To: Miguel Ojeda, Anna-Maria Behnsen, Frederic Weisbecker,
Thomas Gleixner, Danilo Krummrich
Cc: Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Alice Ryhl, Trevor Gross, Lyude Paul, Guangbo Cui,
Dirk Behme, Daniel Almeida, rust-for-linux, linux-kernel,
Andreas Hindborg
Allow `Pin<Box<T>>` to be the target of a timer callback.
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
rust/kernel/time/hrtimer.rs | 3 ++
rust/kernel/time/hrtimer/tbox.rs | 102 +++++++++++++++++++++++++++++++++++++++
2 files changed, 105 insertions(+)
diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs
index c223f1385c723a0b75e7f8184deadbca38872e0a..46dbf0d7fe30d271a2b76af89cc4e9e18b42a19a 100644
--- a/rust/kernel/time/hrtimer.rs
+++ b/rust/kernel/time/hrtimer.rs
@@ -395,6 +395,9 @@ unsafe fn raw_get_timer(ptr: *const Self) ->
}
}
+// `box` is a reserved keyword, so prefix with `t` for timer
+mod tbox;
+
mod arc;
mod pin;
mod pin_mut;
diff --git a/rust/kernel/time/hrtimer/tbox.rs b/rust/kernel/time/hrtimer/tbox.rs
new file mode 100644
index 0000000000000000000000000000000000000000..4b932a20cf6fcacdff7c40fc280f8d73a45addc0
--- /dev/null
+++ b/rust/kernel/time/hrtimer/tbox.rs
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: GPL-2.0
+
+use super::HasTimer;
+use super::RawTimerCallback;
+use super::Timer;
+use super::TimerCallback;
+use super::TimerHandle;
+use super::TimerPointer;
+use crate::prelude::*;
+use crate::time::Ktime;
+use core::mem::ManuallyDrop;
+
+/// A handle for a `Box<HasTimer<U>>` returned by a call to
+/// [`TimerPointer::start`].
+pub struct BoxTimerHandle<U, A>
+where
+ U: HasTimer<U>,
+ A: crate::alloc::Allocator,
+{
+ pub(crate) inner: *mut U,
+ _p: core::marker::PhantomData<A>,
+}
+
+// SAFETY: We implement drop below, and we cancel the timer in the drop
+// implementation.
+unsafe impl<U, A> TimerHandle for BoxTimerHandle<U, A>
+where
+ U: HasTimer<U>,
+ A: crate::alloc::Allocator,
+{
+ fn cancel(&mut self) -> bool {
+ // SAFETY: As we obtained `self.inner` from a valid reference when we
+ // created `self`, it must point to a valid `U`.
+ let timer_ptr = unsafe { <U as HasTimer<U>>::raw_get_timer(self.inner) };
+
+ // SAFETY: As `timer_ptr` points into `U` and `U` is valid, `timer_ptr`
+ // must point to a valid `Timer` instance.
+ unsafe { Timer::<U>::raw_cancel(timer_ptr) }
+ }
+}
+
+impl<U, A> Drop for BoxTimerHandle<U, A>
+where
+ U: HasTimer<U>,
+ A: crate::alloc::Allocator,
+{
+ fn drop(&mut self) {
+ self.cancel();
+ // SAFETY: `self.inner` came from a `Box::into_raw` call
+ drop(unsafe { Box::<U, A>::from_raw(self.inner) })
+ }
+}
+
+impl<U, A> TimerPointer for Pin<Box<U, A>>
+where
+ U: Send + Sync,
+ U: HasTimer<U>,
+ U: for<'a> TimerCallback<CallbackTarget<'a> = Pin<Box<U, A>>>,
+ U: for<'a> TimerCallback<CallbackTargetParameter<'a> = Pin<&'a U>>,
+ A: crate::alloc::Allocator,
+{
+ type TimerHandle = BoxTimerHandle<U, A>;
+
+ fn start(self, expires: Ktime) -> Self::TimerHandle {
+ let self_ptr: *const U = <Self as core::ops::Deref>::deref(&self);
+
+ // SAFETY: Since we generate the pointer passed to `start` from a valid
+ // reference, it is a valid pointer.
+ unsafe { U::start(self_ptr, expires) };
+
+ // SAFETY: We will not move out of this box during timer callback (we
+ // pass an immutable reference to the callback).
+ let inner = unsafe { Pin::into_inner_unchecked(self) };
+
+ BoxTimerHandle {
+ inner: Box::into_raw(inner),
+ _p: core::marker::PhantomData,
+ }
+ }
+}
+
+impl<U, A> RawTimerCallback for Pin<Box<U, A>>
+where
+ U: HasTimer<U>,
+ U: for<'a> TimerCallback<CallbackTarget<'a> = Pin<Box<U, A>>>,
+ U: for<'a> TimerCallback<CallbackTargetParameter<'a> = Pin<&'a U>>,
+ A: crate::alloc::Allocator,
+{
+ unsafe extern "C" fn run(ptr: *mut bindings::hrtimer) -> bindings::hrtimer_restart {
+ // `Timer` is `repr(C)`
+ let timer_ptr = ptr.cast::<super::Timer<U>>();
+
+ // SAFETY: By C API contract `ptr` is the pointer we passed when
+ // queuing the timer, so it is a `Timer<T>` embedded in a `T`.
+ let data_ptr = unsafe { U::timer_container_of(timer_ptr) };
+
+ // SAFETY: We called `Box::into_raw` when we queued the timer.
+ let tbox = ManuallyDrop::new(Box::into_pin(unsafe { Box::<U, A>::from_raw(data_ptr) }));
+
+ U::run(tbox.as_ref()).into()
+ }
+}
--
2.47.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v5 12/14] rust: hrtimer: add `TimerMode`
2024-12-17 15:17 [PATCH v5 00/14] hrtimer Rust API Andreas Hindborg
` (10 preceding siblings ...)
2024-12-17 15:17 ` [PATCH v5 11/14] rust: hrtimer: implement `TimerPointer` for `Pin<Box<T>>` Andreas Hindborg
@ 2024-12-17 15:17 ` 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
13 siblings, 0 replies; 18+ messages in thread
From: Andreas Hindborg @ 2024-12-17 15:17 UTC (permalink / raw)
To: Miguel Ojeda, Anna-Maria Behnsen, Frederic Weisbecker,
Thomas Gleixner, Danilo Krummrich
Cc: Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Alice Ryhl, Trevor Gross, Lyude Paul, Guangbo Cui,
Dirk Behme, Daniel Almeida, rust-for-linux, linux-kernel,
Andreas Hindborg
Allow selection of timer mode by passing a `TimerMode` variant to
`Timer::new`.
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
rust/kernel/time/hrtimer.rs | 87 +++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 84 insertions(+), 3 deletions(-)
diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs
index 46dbf0d7fe30d271a2b76af89cc4e9e18b42a19a..17cf7c1d704d5e900ad4d08e642e02b1e518badf 100644
--- a/rust/kernel/time/hrtimer.rs
+++ b/rust/kernel/time/hrtimer.rs
@@ -43,6 +43,8 @@
pub struct Timer<U> {
#[pin]
timer: Opaque<bindings::hrtimer>,
+ // This field goes away when `bindings::hrtimer_setup` is added.
+ mode: TimerMode,
_t: PhantomData<U>,
}
@@ -55,7 +57,7 @@ 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>
+ pub fn new(mode: TimerMode) -> impl PinInit<Self>
where
T: TimerCallback,
{
@@ -70,10 +72,11 @@ pub fn new() -> impl PinInit<Self>
place,
Some(T::CallbackTarget::run),
bindings::CLOCK_MONOTONIC as i32,
- bindings::hrtimer_mode_HRTIMER_MODE_REL,
+ mode.into(),
);
}
}),
+ mode: mode,
_t: PhantomData,
})
}
@@ -322,7 +325,7 @@ unsafe fn start(self_ptr: *const Self, expires: Ktime) {
Self::c_timer_ptr(self_ptr).cast_mut(),
expires.to_ns(),
0,
- bindings::hrtimer_mode_HRTIMER_MODE_REL,
+ (*Self::raw_get_timer(self_ptr)).mode.into(),
);
}
}
@@ -363,6 +366,84 @@ fn from(value: TimerRestart) -> Self {
}
}
+/// Operational mode of [`Timer`].
+#[derive(Clone, Copy)]
+pub enum TimerMode {
+ /// Timer expires at the given expiration time.
+ Absolute,
+ /// Timer expires after the given expiration time interpreted as a duration from now.
+ Relative,
+ /// Timer does not move between CPU cores.
+ Pinned,
+ /// Timer handler is executed in soft irq context.
+ Soft,
+ /// Timer handler is executed in hard irq context.
+ Hard,
+ /// Timer expires at the given expiration time.
+ /// Timer does not move between CPU cores.
+ AbsolutePinned,
+ /// Timer expires after the given expiration time interpreted as a duration from now.
+ /// Timer does not move between CPU cores.
+ RelativePinned,
+ /// Timer expires at the given expiration time.
+ /// Timer handler is executed in soft irq context.
+ AbsoluteSoft,
+ /// Timer expires after the given expiration time interpreted as a duration from now.
+ /// Timer handler is executed in soft irq context.
+ RelativeSoft,
+ /// Timer expires at the given expiration time.
+ /// Timer does not move between CPU cores.
+ /// Timer handler is executed in soft irq context.
+ AbsolutePinnedSoft,
+ /// Timer expires after the given expiration time interpreted as a duration from now.
+ /// Timer does not move between CPU cores.
+ /// Timer handler is executed in soft irq context.
+ RelativePinnedSoft,
+ /// Timer expires at the given expiration time.
+ /// Timer handler is executed in hard irq context.
+ AbsoluteHard,
+ /// Timer expires after the given expiration time interpreted as a duration from now.
+ /// Timer handler is executed in hard irq context.
+ RelativeHard,
+ /// Timer expires at the given expiration time.
+ /// Timer does not move between CPU cores.
+ /// Timer handler is executed in hard irq context.
+ AbsolutePinnedHard,
+ /// Timer expires after the given expiration time interpreted as a duration from now.
+ /// Timer does not move between CPU cores.
+ /// Timer handler is executed in hard irq context.
+ RelativePinnedHard,
+}
+
+impl From<TimerMode> for bindings::hrtimer_mode {
+ fn from(value: TimerMode) -> Self {
+ use bindings::*;
+ match value {
+ TimerMode::Absolute => hrtimer_mode_HRTIMER_MODE_ABS,
+ TimerMode::Relative => hrtimer_mode_HRTIMER_MODE_REL,
+ TimerMode::Pinned => hrtimer_mode_HRTIMER_MODE_PINNED,
+ TimerMode::Soft => hrtimer_mode_HRTIMER_MODE_SOFT,
+ TimerMode::Hard => hrtimer_mode_HRTIMER_MODE_HARD,
+ TimerMode::AbsolutePinned => hrtimer_mode_HRTIMER_MODE_ABS_PINNED,
+ TimerMode::RelativePinned => hrtimer_mode_HRTIMER_MODE_REL_PINNED,
+ TimerMode::AbsoluteSoft => hrtimer_mode_HRTIMER_MODE_ABS_SOFT,
+ TimerMode::RelativeSoft => hrtimer_mode_HRTIMER_MODE_REL_SOFT,
+ TimerMode::AbsolutePinnedSoft => hrtimer_mode_HRTIMER_MODE_ABS_PINNED_SOFT,
+ TimerMode::RelativePinnedSoft => hrtimer_mode_HRTIMER_MODE_REL_PINNED_SOFT,
+ TimerMode::AbsoluteHard => hrtimer_mode_HRTIMER_MODE_ABS_HARD,
+ TimerMode::RelativeHard => hrtimer_mode_HRTIMER_MODE_REL_HARD,
+ TimerMode::AbsolutePinnedHard => hrtimer_mode_HRTIMER_MODE_ABS_PINNED_HARD,
+ TimerMode::RelativePinnedHard => hrtimer_mode_HRTIMER_MODE_REL_PINNED_HARD,
+ }
+ }
+}
+
+impl From<TimerMode> for u64 {
+ fn from(value: TimerMode) -> Self {
+ Into::<bindings::hrtimer_mode>::into(value) as u64
+ }
+}
+
/// Use to implement the [`HasTimer<T>`] trait.
///
/// See [`module`] documentation for an example.
--
2.47.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v5 13/14] rust: hrtimer: add clocksource selection through `ClockSource`
2024-12-17 15:17 [PATCH v5 00/14] hrtimer Rust API Andreas Hindborg
` (11 preceding siblings ...)
2024-12-17 15:17 ` [PATCH v5 12/14] rust: hrtimer: add `TimerMode` Andreas Hindborg
@ 2024-12-17 15:17 ` Andreas Hindborg
2024-12-17 15:17 ` [PATCH v5 14/14] rust: hrtimer: add maintainer entry Andreas Hindborg
13 siblings, 0 replies; 18+ messages in thread
From: Andreas Hindborg @ 2024-12-17 15:17 UTC (permalink / raw)
To: Miguel Ojeda, Anna-Maria Behnsen, Frederic Weisbecker,
Thomas Gleixner, Danilo Krummrich
Cc: Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Alice Ryhl, Trevor Gross, Lyude Paul, Guangbo Cui,
Dirk Behme, Daniel Almeida, rust-for-linux, linux-kernel,
Andreas Hindborg
Allow selecting a clock source for timers by passing a `ClockSource`
variant to `Timer::new`.
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
rust/kernel/time/hrtimer.rs | 52 +++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 50 insertions(+), 2 deletions(-)
diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs
index 17cf7c1d704d5e900ad4d08e642e02b1e518badf..f9be0fa43c896a09439601bea825e5b17d0e995d 100644
--- a/rust/kernel/time/hrtimer.rs
+++ b/rust/kernel/time/hrtimer.rs
@@ -57,7 +57,7 @@ unsafe impl<U> Sync for Timer<U> {}
impl<T> Timer<T> {
/// Return an initializer for a new timer instance.
- pub fn new(mode: TimerMode) -> impl PinInit<Self>
+ pub fn new(mode: TimerMode, clock: ClockSource) -> impl PinInit<Self>
where
T: TimerCallback,
{
@@ -71,7 +71,7 @@ pub fn new(mode: TimerMode) -> impl PinInit<Self>
bindings::hrtimer_setup(
place,
Some(T::CallbackTarget::run),
- bindings::CLOCK_MONOTONIC as i32,
+ clock.into(),
mode.into(),
);
}
@@ -444,6 +444,54 @@ fn from(value: TimerMode) -> Self {
}
}
+/// The clock source to use for a [`Timer`].
+pub enum ClockSource {
+ /// A settable system-wide clock that measures real (i.e., wall-clock) time.
+ /// Setting this clock requires appropriate privileges. This clock is
+ /// affected by discontinuous jumps in the system time (e.g., if the system
+ /// administrator manually changes the clock), and by frequency adjustments
+ /// performed by NTP and similar applications via adjtime(3), adjtimex(2),
+ /// clock_adjtime(2), and ntp_adjtime(3). This clock normally counts the
+ /// number of seconds since 1970-01-01 00:00:00 Coordinated Universal Time
+ /// (UTC) except that it ignores leap seconds; near a leap second it is
+ /// typically adjusted by NTP to stay roughly in sync with UTC.
+ RealTime,
+ /// A nonsettable system-wide clock that represents monotonic time since—as
+ /// described by POSIX—"some unspecified point in the past". On Linux, that
+ /// point corresponds to the number of seconds that the system has been
+ /// running since it was booted.
+ ///
+ /// The CLOCK_MONOTONIC clock is not affected by discontinuous jumps in the
+ /// system time (e.g., if the system administrator manually changes the
+ /// clock), but is affected by frequency adjustments. This clock does not
+ /// count time that the system is suspended.
+ Monotonic,
+ /// A nonsettable system-wide clock that is identical to CLOCK_MONOTONIC,
+ /// except that it also includes any time that the system is suspended. This
+ /// allows applications to get a suspend-aware monotonic clock without
+ /// having to deal with the complications of CLOCK_REALTIME, which may have
+ /// discontinuities if the time is changed using settimeofday(2) or similar.
+ BootTime,
+ /// A nonsettable system-wide clock derived from wall-clock time but
+ /// counting leap seconds. This clock does not experience discontinuities or
+ /// frequency adjustments caused by inserting leap seconds as CLOCK_REALTIME
+ /// does.
+ ///
+ /// The acronym TAI refers to International Atomic Time.
+ TAI,
+}
+
+impl From<ClockSource> for bindings::clockid_t {
+ fn from(value: ClockSource) -> Self {
+ match value {
+ ClockSource::RealTime => bindings::CLOCK_REALTIME as i32,
+ ClockSource::Monotonic => bindings::CLOCK_MONOTONIC as i32,
+ ClockSource::BootTime => bindings::CLOCK_BOOTTIME as i32,
+ ClockSource::TAI => bindings::CLOCK_TAI as i32,
+ }
+ }
+}
+
/// Use to implement the [`HasTimer<T>`] trait.
///
/// See [`module`] documentation for an example.
--
2.47.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v5 14/14] rust: hrtimer: add maintainer entry
2024-12-17 15:17 [PATCH v5 00/14] hrtimer Rust API Andreas Hindborg
` (12 preceding siblings ...)
2024-12-17 15:17 ` [PATCH v5 13/14] rust: hrtimer: add clocksource selection through `ClockSource` Andreas Hindborg
@ 2024-12-17 15:17 ` Andreas Hindborg
13 siblings, 0 replies; 18+ messages in thread
From: Andreas Hindborg @ 2024-12-17 15:17 UTC (permalink / raw)
To: Miguel Ojeda, Anna-Maria Behnsen, Frederic Weisbecker,
Thomas Gleixner, Danilo Krummrich
Cc: Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Alice Ryhl, Trevor Gross, Lyude Paul, Guangbo Cui,
Dirk Behme, Daniel Almeida, rust-for-linux, linux-kernel,
Andreas Hindborg
Add Andreas Hindborg as maintainer for Rust `hrtimer` abstractions. Also
add Boqun Feng as reviewer.
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
Acked-by: Boqun Feng <boqun.feng@gmail.com>
---
MAINTAINERS | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 1e930c7a58b13d8bbe6bf133ba7b36aa24c2b5e0..335ef0807516f047b5c84727f0276c4e88141c49 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10251,6 +10251,16 @@ F: kernel/time/timer_list.c
F: kernel/time/timer_migration.*
F: tools/testing/selftests/timers/
+HIGH-RESOLUTION TIMERS [RUST]
+M: Andreas Hindborg <a.hindborg@kernel.org>
+R: Boqun Feng <boqun.feng@gmail.com>
+L: rust-for-linux@vger.kernel.org
+S: Supported
+W: https://rust-for-linux.com
+B: https://github.com/Rust-for-Linux/linux/issues
+F: rust/kernel/time/hrtimer.rs
+F: rust/kernel/time/hrtimer/
+
HIGH-SPEED SCC DRIVER FOR AX.25
L: linux-hams@vger.kernel.org
S: Orphan
--
2.47.0
^ permalink raw reply related [flat|nested] 18+ messages in thread