From: Andreas Hindborg Date: Sun, 9 Mar 2025 15:18:54 +0000 (+0100) Subject: rust: hrtimer: implement `HrTimerPointer` for `Arc` X-Git-Tag: v6.15-rc1~93^2^2~10 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d7bf4786b5250b0e490a937d1f8a16ee3a54adbe;p=thirdparty%2Fkernel%2Flinux.git 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 Acked-by: Thomas Gleixner Reviewed-by: Lyude Paul Reviewed-by: Benno Lossin Link: https://lore.kernel.org/r/20250309-hrtimer-v3-v6-12-rc2-v12-3-73586e2bd5f1@kernel.org Signed-off-by: Andreas Hindborg --- diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs index a3697622fa170..bfb536f2a4903 100644 --- a/rust/kernel/time/hrtimer.rs +++ b/rust/kernel/time/hrtimer.rs @@ -150,7 +150,6 @@ impl HrTimer { /// # 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 0000000000000..df97fade0aa12 --- /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>` returned by a call to +/// [`HrTimerPointer::start`]. +pub struct ArcHrTimerHandle +where + T: HasHrTimer, +{ + pub(crate) inner: Arc, +} + +// SAFETY: We implement drop below, and we cancel the timer in the drop +// implementation. +unsafe impl HrTimerHandle for ArcHrTimerHandle +where + T: HasHrTimer, +{ + 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 { >::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::::raw_cancel(timer_ptr) } + } +} + +impl Drop for ArcHrTimerHandle +where + T: HasHrTimer, +{ + fn drop(&mut self) { + self.cancel(); + } +} + +impl HrTimerPointer for Arc +where + T: 'static, + T: Send + Sync, + T: HasHrTimer, + T: for<'a> HrTimerCallback = Self>, +{ + type TimerHandle = ArcHrTimerHandle; + + fn start(self, expires: Ktime) -> ArcHrTimerHandle { + // 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 RawHrTimerCallback for Arc +where + T: 'static, + T: HasHrTimer, + T: for<'a> HrTimerCallback = 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::>(); + + // SAFETY: By C API contract `ptr` is the pointer we passed when + // queuing the timer, so it is a `HrTimer` 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 + } +}