mirror of
https://github.com/torvalds/linux.git
synced 2026-05-12 16:18:45 +02:00
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>
This commit is contained in:
parent
a0c6fa8b8a
commit
d7bf4786b5
|
|
@ -150,7 +150,6 @@ unsafe fn raw_get(this: *const Self) -> *mut bindings::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 @@ unsafe fn timer_container_of(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod arc;
|
||||
pub use arc::ArcHrTimerHandle;
|
||||
|
|
|
|||
102
rust/kernel/time/hrtimer/arc.rs
Normal file
102
rust/kernel/time/hrtimer/arc.rs
Normal file
|
|
@ -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
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user