mirror of
https://github.com/torvalds/linux.git
synced 2025-08-16 22:51:39 +02:00
rust: time: Make HasHrTimer generic over HrTimerMode
Add a `TimerMode` associated type to the `HasHrTimer` trait to represent the operational mode of the timer, such as absolute or relative expiration. This new type must implement the `HrTimerMode` trait, which defines how expiration values are interpreted. Update the `start()` method to accept an `expires` parameter of type `<Self::TimerMode as HrTimerMode>::Expires` instead of the fixed `Ktime`. This enables different timer modes to provide strongly typed expiration values, such as `Instant<C>` or `Delta`. The `impl_has_hr_timer` macro is also extended to allow specifying the `HrTimerMode`. In the following example, it guarantees that the `start()` method for `Foo` only accepts `Instant<Monotonic>`. Using a `Delta` or an `Instant` with a different clock source will result in a compile-time error: struct Foo { #[pin] timer: HrTimer<Self>, } impl_has_hr_timer! { impl HasHrTimer<Self> for Foo { mode : AbsoluteMode<Monotonic>, field : self.timer } } This design eliminates runtime mismatches between expires types and clock sources, and enables stronger type-level guarantees throughout hrtimer. Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com> Reviewed-by: Andreas Hindborg <a.hindborg@kernel.org> Link: https://lore.kernel.org/r/20250610132823.3457263-5-fujita.tomonori@gmail.com [ changed conversion method names to `as_*` - Andreas ] Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
This commit is contained in:
parent
d9fc00dc73
commit
e0c0ab04f6
5 changed files with 66 additions and 21 deletions
|
@ -98,7 +98,6 @@ impl Ktime {
|
||||||
pub struct HrTimer<T> {
|
pub struct HrTimer<T> {
|
||||||
#[pin]
|
#[pin]
|
||||||
timer: Opaque<bindings::hrtimer>,
|
timer: Opaque<bindings::hrtimer>,
|
||||||
mode: bindings::hrtimer_mode,
|
|
||||||
_t: PhantomData<T>,
|
_t: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,9 +111,10 @@ unsafe impl<T> Sync for HrTimer<T> {}
|
||||||
|
|
||||||
impl<T> HrTimer<T> {
|
impl<T> HrTimer<T> {
|
||||||
/// Return an initializer for a new timer instance.
|
/// Return an initializer for a new timer instance.
|
||||||
pub fn new<U: ClockSource, M: HrTimerMode>() -> impl PinInit<Self>
|
pub fn new() -> impl PinInit<Self>
|
||||||
where
|
where
|
||||||
T: HrTimerCallback,
|
T: HrTimerCallback,
|
||||||
|
T: HasHrTimer<T>,
|
||||||
{
|
{
|
||||||
pin_init!(Self {
|
pin_init!(Self {
|
||||||
// INVARIANT: We initialize `timer` with `hrtimer_setup` below.
|
// INVARIANT: We initialize `timer` with `hrtimer_setup` below.
|
||||||
|
@ -126,12 +126,11 @@ impl<T> HrTimer<T> {
|
||||||
bindings::hrtimer_setup(
|
bindings::hrtimer_setup(
|
||||||
place,
|
place,
|
||||||
Some(T::Pointer::run),
|
Some(T::Pointer::run),
|
||||||
U::ID,
|
<<T as HasHrTimer<T>>::TimerMode as HrTimerMode>::Clock::ID,
|
||||||
M::C_MODE,
|
<T as HasHrTimer<T>>::TimerMode::C_MODE,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
mode: M::C_MODE,
|
|
||||||
_t: PhantomData,
|
_t: PhantomData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -193,6 +192,11 @@ impl<T> HrTimer<T> {
|
||||||
/// exist. A timer can be manipulated through any of the handles, and a handle
|
/// exist. A timer can be manipulated through any of the handles, and a handle
|
||||||
/// may represent a cancelled timer.
|
/// may represent a cancelled timer.
|
||||||
pub trait HrTimerPointer: Sync + Sized {
|
pub trait HrTimerPointer: Sync + Sized {
|
||||||
|
/// The operational mode associated with this timer.
|
||||||
|
///
|
||||||
|
/// This defines how the expiration value is interpreted.
|
||||||
|
type TimerMode: HrTimerMode;
|
||||||
|
|
||||||
/// A handle representing a started or restarted timer.
|
/// A handle representing a started or restarted timer.
|
||||||
///
|
///
|
||||||
/// If the timer is running or if the timer callback is executing when the
|
/// If the timer is running or if the timer callback is executing when the
|
||||||
|
@ -205,7 +209,7 @@ pub trait HrTimerPointer: Sync + Sized {
|
||||||
|
|
||||||
/// Start the timer with expiry after `expires` time units. If the timer was
|
/// Start the timer with expiry after `expires` time units. If the timer was
|
||||||
/// already running, it is restarted with the new expiry time.
|
/// already running, it is restarted with the new expiry time.
|
||||||
fn start(self, expires: Ktime) -> Self::TimerHandle;
|
fn start(self, expires: <Self::TimerMode as HrTimerMode>::Expires) -> Self::TimerHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unsafe version of [`HrTimerPointer`] for situations where leaking the
|
/// Unsafe version of [`HrTimerPointer`] for situations where leaking the
|
||||||
|
@ -220,6 +224,11 @@ pub trait HrTimerPointer: Sync + Sized {
|
||||||
/// [`UnsafeHrTimerPointer`] outlives any associated [`HrTimerPointer::TimerHandle`]
|
/// [`UnsafeHrTimerPointer`] outlives any associated [`HrTimerPointer::TimerHandle`]
|
||||||
/// instances.
|
/// instances.
|
||||||
pub unsafe trait UnsafeHrTimerPointer: Sync + Sized {
|
pub unsafe trait UnsafeHrTimerPointer: Sync + Sized {
|
||||||
|
/// The operational mode associated with this timer.
|
||||||
|
///
|
||||||
|
/// This defines how the expiration value is interpreted.
|
||||||
|
type TimerMode: HrTimerMode;
|
||||||
|
|
||||||
/// A handle representing a running timer.
|
/// A handle representing a running timer.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
|
@ -236,7 +245,7 @@ pub unsafe trait UnsafeHrTimerPointer: Sync + Sized {
|
||||||
///
|
///
|
||||||
/// Caller promises keep the timer structure alive until the timer is dead.
|
/// Caller promises keep the timer structure alive until the timer is dead.
|
||||||
/// Caller can ensure this by not leaking the returned [`Self::TimerHandle`].
|
/// Caller can ensure this by not leaking the returned [`Self::TimerHandle`].
|
||||||
unsafe fn start(self, expires: Ktime) -> Self::TimerHandle;
|
unsafe fn start(self, expires: <Self::TimerMode as HrTimerMode>::Expires) -> Self::TimerHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trait for stack allocated timers.
|
/// A trait for stack allocated timers.
|
||||||
|
@ -246,9 +255,14 @@ pub unsafe trait UnsafeHrTimerPointer: Sync + Sized {
|
||||||
/// Implementers must ensure that `start_scoped` does not return until the
|
/// Implementers must ensure that `start_scoped` does not return until the
|
||||||
/// timer is dead and the timer handler is not running.
|
/// timer is dead and the timer handler is not running.
|
||||||
pub unsafe trait ScopedHrTimerPointer {
|
pub unsafe trait ScopedHrTimerPointer {
|
||||||
|
/// The operational mode associated with this timer.
|
||||||
|
///
|
||||||
|
/// This defines how the expiration value is interpreted.
|
||||||
|
type TimerMode: HrTimerMode;
|
||||||
|
|
||||||
/// Start the timer to run after `expires` time units and immediately
|
/// Start the timer to run after `expires` time units and immediately
|
||||||
/// after call `f`. When `f` returns, the timer is cancelled.
|
/// after call `f`. When `f` returns, the timer is cancelled.
|
||||||
fn start_scoped<T, F>(self, expires: Ktime, f: F) -> T
|
fn start_scoped<T, F>(self, expires: <Self::TimerMode as HrTimerMode>::Expires, f: F) -> T
|
||||||
where
|
where
|
||||||
F: FnOnce() -> T;
|
F: FnOnce() -> T;
|
||||||
}
|
}
|
||||||
|
@ -260,7 +274,13 @@ unsafe impl<T> ScopedHrTimerPointer for T
|
||||||
where
|
where
|
||||||
T: UnsafeHrTimerPointer,
|
T: UnsafeHrTimerPointer,
|
||||||
{
|
{
|
||||||
fn start_scoped<U, F>(self, expires: Ktime, f: F) -> U
|
type TimerMode = T::TimerMode;
|
||||||
|
|
||||||
|
fn start_scoped<U, F>(
|
||||||
|
self,
|
||||||
|
expires: <<T as UnsafeHrTimerPointer>::TimerMode as HrTimerMode>::Expires,
|
||||||
|
f: F,
|
||||||
|
) -> U
|
||||||
where
|
where
|
||||||
F: FnOnce() -> U,
|
F: FnOnce() -> U,
|
||||||
{
|
{
|
||||||
|
@ -335,6 +355,11 @@ pub unsafe trait HrTimerHandle {
|
||||||
/// their documentation. All the methods of this trait must operate on the same
|
/// their documentation. All the methods of this trait must operate on the same
|
||||||
/// field.
|
/// field.
|
||||||
pub unsafe trait HasHrTimer<T> {
|
pub unsafe trait HasHrTimer<T> {
|
||||||
|
/// The operational mode associated with this timer.
|
||||||
|
///
|
||||||
|
/// This defines how the expiration value is interpreted.
|
||||||
|
type TimerMode: HrTimerMode;
|
||||||
|
|
||||||
/// Return a pointer to the [`HrTimer`] within `Self`.
|
/// Return a pointer to the [`HrTimer`] within `Self`.
|
||||||
///
|
///
|
||||||
/// This function is useful to get access to the value without creating
|
/// This function is useful to get access to the value without creating
|
||||||
|
@ -382,14 +407,14 @@ pub unsafe trait HasHrTimer<T> {
|
||||||
/// - `this` must point to a valid `Self`.
|
/// - `this` must point to a valid `Self`.
|
||||||
/// - Caller must ensure that the pointee of `this` lives until the timer
|
/// - Caller must ensure that the pointee of `this` lives until the timer
|
||||||
/// fires or is canceled.
|
/// fires or is canceled.
|
||||||
unsafe fn start(this: *const Self, expires: Ktime) {
|
unsafe fn start(this: *const Self, expires: <Self::TimerMode as HrTimerMode>::Expires) {
|
||||||
// SAFETY: By function safety requirement, `this` is a valid `Self`.
|
// SAFETY: By function safety requirement, `this` is a valid `Self`.
|
||||||
unsafe {
|
unsafe {
|
||||||
bindings::hrtimer_start_range_ns(
|
bindings::hrtimer_start_range_ns(
|
||||||
Self::c_timer_ptr(this).cast_mut(),
|
Self::c_timer_ptr(this).cast_mut(),
|
||||||
expires.to_ns(),
|
expires.as_nanos(),
|
||||||
0,
|
0,
|
||||||
(*Self::raw_get_timer(this)).mode,
|
<Self::TimerMode as HrTimerMode>::Clock::ID as u32,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -568,12 +593,16 @@ macro_rules! impl_has_hr_timer {
|
||||||
impl$({$($generics:tt)*})?
|
impl$({$($generics:tt)*})?
|
||||||
HasHrTimer<$timer_type:ty>
|
HasHrTimer<$timer_type:ty>
|
||||||
for $self:ty
|
for $self:ty
|
||||||
{ self.$field:ident }
|
{
|
||||||
|
mode : $mode:ty,
|
||||||
|
field : self.$field:ident $(,)?
|
||||||
|
}
|
||||||
$($rest:tt)*
|
$($rest:tt)*
|
||||||
) => {
|
) => {
|
||||||
// SAFETY: This implementation of `raw_get_timer` only compiles if the
|
// SAFETY: This implementation of `raw_get_timer` only compiles if the
|
||||||
// field has the right type.
|
// field has the right type.
|
||||||
unsafe impl$(<$($generics)*>)? $crate::time::hrtimer::HasHrTimer<$timer_type> for $self {
|
unsafe impl$(<$($generics)*>)? $crate::time::hrtimer::HasHrTimer<$timer_type> for $self {
|
||||||
|
type TimerMode = $mode;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn raw_get_timer(
|
unsafe fn raw_get_timer(
|
||||||
|
|
|
@ -4,8 +4,8 @@ use super::HasHrTimer;
|
||||||
use super::HrTimer;
|
use super::HrTimer;
|
||||||
use super::HrTimerCallback;
|
use super::HrTimerCallback;
|
||||||
use super::HrTimerHandle;
|
use super::HrTimerHandle;
|
||||||
|
use super::HrTimerMode;
|
||||||
use super::HrTimerPointer;
|
use super::HrTimerPointer;
|
||||||
use super::Ktime;
|
|
||||||
use super::RawHrTimerCallback;
|
use super::RawHrTimerCallback;
|
||||||
use crate::sync::Arc;
|
use crate::sync::Arc;
|
||||||
use crate::sync::ArcBorrow;
|
use crate::sync::ArcBorrow;
|
||||||
|
@ -54,9 +54,13 @@ where
|
||||||
T: HasHrTimer<T>,
|
T: HasHrTimer<T>,
|
||||||
T: for<'a> HrTimerCallback<Pointer<'a> = Self>,
|
T: for<'a> HrTimerCallback<Pointer<'a> = Self>,
|
||||||
{
|
{
|
||||||
|
type TimerMode = <T as HasHrTimer<T>>::TimerMode;
|
||||||
type TimerHandle = ArcHrTimerHandle<T>;
|
type TimerHandle = ArcHrTimerHandle<T>;
|
||||||
|
|
||||||
fn start(self, expires: Ktime) -> ArcHrTimerHandle<T> {
|
fn start(
|
||||||
|
self,
|
||||||
|
expires: <<T as HasHrTimer<T>>::TimerMode as HrTimerMode>::Expires,
|
||||||
|
) -> ArcHrTimerHandle<T> {
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// - We keep `self` alive by wrapping it in a handle below.
|
// - We keep `self` alive by wrapping it in a handle below.
|
||||||
// - Since we generate the pointer passed to `start` from a valid
|
// - Since we generate the pointer passed to `start` from a valid
|
||||||
|
|
|
@ -4,7 +4,7 @@ use super::HasHrTimer;
|
||||||
use super::HrTimer;
|
use super::HrTimer;
|
||||||
use super::HrTimerCallback;
|
use super::HrTimerCallback;
|
||||||
use super::HrTimerHandle;
|
use super::HrTimerHandle;
|
||||||
use super::Ktime;
|
use super::HrTimerMode;
|
||||||
use super::RawHrTimerCallback;
|
use super::RawHrTimerCallback;
|
||||||
use super::UnsafeHrTimerPointer;
|
use super::UnsafeHrTimerPointer;
|
||||||
use core::pin::Pin;
|
use core::pin::Pin;
|
||||||
|
@ -54,9 +54,13 @@ where
|
||||||
T: HasHrTimer<T>,
|
T: HasHrTimer<T>,
|
||||||
T: HrTimerCallback<Pointer<'a> = Self>,
|
T: HrTimerCallback<Pointer<'a> = Self>,
|
||||||
{
|
{
|
||||||
|
type TimerMode = <T as HasHrTimer<T>>::TimerMode;
|
||||||
type TimerHandle = PinHrTimerHandle<'a, T>;
|
type TimerHandle = PinHrTimerHandle<'a, T>;
|
||||||
|
|
||||||
unsafe fn start(self, expires: Ktime) -> Self::TimerHandle {
|
unsafe fn start(
|
||||||
|
self,
|
||||||
|
expires: <<T as HasHrTimer<T>>::TimerMode as HrTimerMode>::Expires,
|
||||||
|
) -> Self::TimerHandle {
|
||||||
// Cast to pointer
|
// Cast to pointer
|
||||||
let self_ptr: *const T = self.get_ref();
|
let self_ptr: *const T = self.get_ref();
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
HasHrTimer, HrTimer, HrTimerCallback, HrTimerHandle, Ktime, RawHrTimerCallback,
|
HasHrTimer, HrTimer, HrTimerCallback, HrTimerHandle, HrTimerMode, RawHrTimerCallback,
|
||||||
UnsafeHrTimerPointer,
|
UnsafeHrTimerPointer,
|
||||||
};
|
};
|
||||||
use core::{marker::PhantomData, pin::Pin, ptr::NonNull};
|
use core::{marker::PhantomData, pin::Pin, ptr::NonNull};
|
||||||
|
@ -52,9 +52,13 @@ where
|
||||||
T: HasHrTimer<T>,
|
T: HasHrTimer<T>,
|
||||||
T: HrTimerCallback<Pointer<'a> = Self>,
|
T: HrTimerCallback<Pointer<'a> = Self>,
|
||||||
{
|
{
|
||||||
|
type TimerMode = <T as HasHrTimer<T>>::TimerMode;
|
||||||
type TimerHandle = PinMutHrTimerHandle<'a, T>;
|
type TimerHandle = PinMutHrTimerHandle<'a, T>;
|
||||||
|
|
||||||
unsafe fn start(mut self, expires: Ktime) -> Self::TimerHandle {
|
unsafe fn start(
|
||||||
|
mut self,
|
||||||
|
expires: <<T as HasHrTimer<T>>::TimerMode as HrTimerMode>::Expires,
|
||||||
|
) -> Self::TimerHandle {
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// - We promise not to move out of `self`. We only pass `self`
|
// - We promise not to move out of `self`. We only pass `self`
|
||||||
// back to the caller as a `Pin<&mut self>`.
|
// back to the caller as a `Pin<&mut self>`.
|
||||||
|
|
|
@ -4,8 +4,8 @@ use super::HasHrTimer;
|
||||||
use super::HrTimer;
|
use super::HrTimer;
|
||||||
use super::HrTimerCallback;
|
use super::HrTimerCallback;
|
||||||
use super::HrTimerHandle;
|
use super::HrTimerHandle;
|
||||||
|
use super::HrTimerMode;
|
||||||
use super::HrTimerPointer;
|
use super::HrTimerPointer;
|
||||||
use super::Ktime;
|
|
||||||
use super::RawHrTimerCallback;
|
use super::RawHrTimerCallback;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use core::ptr::NonNull;
|
use core::ptr::NonNull;
|
||||||
|
@ -64,9 +64,13 @@ where
|
||||||
T: for<'a> HrTimerCallback<Pointer<'a> = Pin<Box<T, A>>>,
|
T: for<'a> HrTimerCallback<Pointer<'a> = Pin<Box<T, A>>>,
|
||||||
A: crate::alloc::Allocator,
|
A: crate::alloc::Allocator,
|
||||||
{
|
{
|
||||||
|
type TimerMode = <T as HasHrTimer<T>>::TimerMode;
|
||||||
type TimerHandle = BoxHrTimerHandle<T, A>;
|
type TimerHandle = BoxHrTimerHandle<T, A>;
|
||||||
|
|
||||||
fn start(self, expires: Ktime) -> Self::TimerHandle {
|
fn start(
|
||||||
|
self,
|
||||||
|
expires: <<T as HasHrTimer<T>>::TimerMode as HrTimerMode>::Expires,
|
||||||
|
) -> Self::TimerHandle {
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// - We will not move out of this box during timer callback (we pass an
|
// - We will not move out of this box during timer callback (we pass an
|
||||||
// immutable reference to the callback).
|
// immutable reference to the callback).
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue