diff options
author | Andreas Hindborg <a.hindborg@kernel.org> | 2025-03-09 16:18:54 +0100 |
---|---|---|
committer | Andreas Hindborg <a.hindborg@kernel.org> | 2025-03-11 21:00:42 +0100 |
commit | d7bf4786b5250b0e490a937d1f8a16ee3a54adbe (patch) | |
tree | 9114fadb30e3f333f257d7ef39a4fbf1ea8d1161 /rust | |
parent | a0c6fa8b8a59f8901e182fada6ac0e1f65beaa00 (diff) |
rust: hrtimer: implement `HrTimerPointer` for `Arc`
Allow the use of intrusive `hrtimer` fields in structs that are managed by
an `Arc` by implementing `HrTimerPointer` and `RawTimerCallbck` for `Arc`.
Acked-by: Frederic Weisbecker <frederic@kernel.org>
Acked-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Lyude Paul <lyude@redhat.com>
Reviewed-by: Benno Lossin <benno.lossin@proton.me>
Link: https://lore.kernel.org/r/20250309-hrtimer-v3-v6-12-rc2-v12-3-73586e2bd5f1@kernel.org
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
Diffstat (limited to 'rust')
-rw-r--r-- | rust/kernel/time/hrtimer.rs | 4 | ||||
-rw-r--r-- | rust/kernel/time/hrtimer/arc.rs | 102 |
2 files changed, 105 insertions, 1 deletions
diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs index a3697622fa17..bfb536f2a490 100644 --- a/rust/kernel/time/hrtimer.rs +++ b/rust/kernel/time/hrtimer.rs @@ -150,7 +150,6 @@ impl<T> HrTimer<T> { /// # Safety /// /// `this` must point to a valid `Self`. - #[allow(dead_code)] pub(crate) unsafe fn raw_cancel(this: *const Self) -> bool { // SAFETY: `this` points to an allocation of at least `HrTimer` size. let c_timer_ptr = unsafe { HrTimer::raw_get(this) }; @@ -349,3 +348,6 @@ macro_rules! impl_has_hr_timer { } } } + +mod arc; +pub use arc::ArcHrTimerHandle; diff --git a/rust/kernel/time/hrtimer/arc.rs b/rust/kernel/time/hrtimer/arc.rs new file mode 100644 index 000000000000..df97fade0aa1 --- /dev/null +++ b/rust/kernel/time/hrtimer/arc.rs @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0 + +use super::HasHrTimer; +use super::HrTimer; +use super::HrTimerCallback; +use super::HrTimerHandle; +use super::HrTimerPointer; +use super::RawHrTimerCallback; +use crate::sync::Arc; +use crate::sync::ArcBorrow; +use crate::time::Ktime; + +/// A handle for an `Arc<HasHrTimer<T>>` returned by a call to +/// [`HrTimerPointer::start`]. +pub struct ArcHrTimerHandle<T> +where + T: HasHrTimer<T>, +{ + pub(crate) inner: Arc<T>, +} + +// SAFETY: We implement drop below, and we cancel the timer in the drop +// implementation. +unsafe impl<T> HrTimerHandle for ArcHrTimerHandle<T> +where + T: HasHrTimer<T>, +{ + 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 `T`. + let timer_ptr = unsafe { <T as HasHrTimer<T>>::raw_get_timer(self_ptr) }; + + // SAFETY: As `timer_ptr` points into `T` and `T` is valid, `timer_ptr` + // must point to a valid `HrTimer` instance. + unsafe { HrTimer::<T>::raw_cancel(timer_ptr) } + } +} + +impl<T> Drop for ArcHrTimerHandle<T> +where + T: HasHrTimer<T>, +{ + fn drop(&mut self) { + self.cancel(); + } +} + +impl<T> HrTimerPointer for Arc<T> +where + T: 'static, + T: Send + Sync, + T: HasHrTimer<T>, + T: for<'a> HrTimerCallback<Pointer<'a> = Self>, +{ + type TimerHandle = ArcHrTimerHandle<T>; + + fn start(self, expires: Ktime) -> ArcHrTimerHandle<T> { + // SAFETY: + // - We keep `self` alive by wrapping it in a handle below. + // - Since we generate the pointer passed to `start` from a valid + // reference, it is a valid pointer. + unsafe { T::start(Arc::as_ptr(&self), expires) }; + ArcHrTimerHandle { inner: self } + } +} + +impl<T> RawHrTimerCallback for Arc<T> +where + T: 'static, + T: HasHrTimer<T>, + T: for<'a> HrTimerCallback<Pointer<'a> = Self>, +{ + type CallbackTarget<'a> = ArcBorrow<'a, T>; + + unsafe extern "C" fn run(ptr: *mut bindings::hrtimer) -> bindings::hrtimer_restart { + // `HrTimer` is `repr(C)` + let timer_ptr = ptr.cast::<super::HrTimer<T>>(); + + // SAFETY: By C API contract `ptr` is the pointer we passed when + // queuing the timer, so it is a `HrTimer<T>` embedded in a `T`. + let data_ptr = unsafe { T::timer_container_of(timer_ptr) }; + + // SAFETY: + // - `data_ptr` is derived form the pointer to the `T` that was used to + // queue the timer. + // - As per the safety requirements of the trait `HrTimerHandle`, the + // `ArcHrTimerHandle` associated with this timer is guaranteed to + // be alive until this method returns. That handle borrows the `T` + // behind `data_ptr` thus guaranteeing the validity of + // the `ArcBorrow` created below. + // - We own one refcount in the `ArcTimerHandle` associated with this + // timer, so it is not possible to get a `UniqueArc` to this + // allocation from other `Arc` clones. + let receiver = unsafe { ArcBorrow::from_raw(data_ptr) }; + + T::run(receiver); + + bindings::hrtimer_restart_HRTIMER_NORESTART + } +} |