Skip to content

Commit d7bf478

Browse files
author
Andreas Hindborg
committed
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 <[email protected]> Acked-by: Thomas Gleixner <[email protected]> Reviewed-by: Lyude Paul <[email protected]> Reviewed-by: Benno Lossin <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Andreas Hindborg <[email protected]>
1 parent a0c6fa8 commit d7bf478

File tree

2 files changed

+105
-1
lines changed

2 files changed

+105
-1
lines changed

rust/kernel/time/hrtimer.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,6 @@ impl<T> HrTimer<T> {
150150
/// # Safety
151151
///
152152
/// `this` must point to a valid `Self`.
153-
#[allow(dead_code)]
154153
pub(crate) unsafe fn raw_cancel(this: *const Self) -> bool {
155154
// SAFETY: `this` points to an allocation of at least `HrTimer` size.
156155
let c_timer_ptr = unsafe { HrTimer::raw_get(this) };
@@ -349,3 +348,6 @@ macro_rules! impl_has_hr_timer {
349348
}
350349
}
351350
}
351+
352+
mod arc;
353+
pub use arc::ArcHrTimerHandle;

rust/kernel/time/hrtimer/arc.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
use super::HasHrTimer;
4+
use super::HrTimer;
5+
use super::HrTimerCallback;
6+
use super::HrTimerHandle;
7+
use super::HrTimerPointer;
8+
use super::RawHrTimerCallback;
9+
use crate::sync::Arc;
10+
use crate::sync::ArcBorrow;
11+
use crate::time::Ktime;
12+
13+
/// A handle for an `Arc<HasHrTimer<T>>` returned by a call to
14+
/// [`HrTimerPointer::start`].
15+
pub struct ArcHrTimerHandle<T>
16+
where
17+
T: HasHrTimer<T>,
18+
{
19+
pub(crate) inner: Arc<T>,
20+
}
21+
22+
// SAFETY: We implement drop below, and we cancel the timer in the drop
23+
// implementation.
24+
unsafe impl<T> HrTimerHandle for ArcHrTimerHandle<T>
25+
where
26+
T: HasHrTimer<T>,
27+
{
28+
fn cancel(&mut self) -> bool {
29+
let self_ptr = Arc::as_ptr(&self.inner);
30+
31+
// SAFETY: As we obtained `self_ptr` from a valid reference above, it
32+
// must point to a valid `T`.
33+
let timer_ptr = unsafe { <T as HasHrTimer<T>>::raw_get_timer(self_ptr) };
34+
35+
// SAFETY: As `timer_ptr` points into `T` and `T` is valid, `timer_ptr`
36+
// must point to a valid `HrTimer` instance.
37+
unsafe { HrTimer::<T>::raw_cancel(timer_ptr) }
38+
}
39+
}
40+
41+
impl<T> Drop for ArcHrTimerHandle<T>
42+
where
43+
T: HasHrTimer<T>,
44+
{
45+
fn drop(&mut self) {
46+
self.cancel();
47+
}
48+
}
49+
50+
impl<T> HrTimerPointer for Arc<T>
51+
where
52+
T: 'static,
53+
T: Send + Sync,
54+
T: HasHrTimer<T>,
55+
T: for<'a> HrTimerCallback<Pointer<'a> = Self>,
56+
{
57+
type TimerHandle = ArcHrTimerHandle<T>;
58+
59+
fn start(self, expires: Ktime) -> ArcHrTimerHandle<T> {
60+
// SAFETY:
61+
// - We keep `self` alive by wrapping it in a handle below.
62+
// - Since we generate the pointer passed to `start` from a valid
63+
// reference, it is a valid pointer.
64+
unsafe { T::start(Arc::as_ptr(&self), expires) };
65+
ArcHrTimerHandle { inner: self }
66+
}
67+
}
68+
69+
impl<T> RawHrTimerCallback for Arc<T>
70+
where
71+
T: 'static,
72+
T: HasHrTimer<T>,
73+
T: for<'a> HrTimerCallback<Pointer<'a> = Self>,
74+
{
75+
type CallbackTarget<'a> = ArcBorrow<'a, T>;
76+
77+
unsafe extern "C" fn run(ptr: *mut bindings::hrtimer) -> bindings::hrtimer_restart {
78+
// `HrTimer` is `repr(C)`
79+
let timer_ptr = ptr.cast::<super::HrTimer<T>>();
80+
81+
// SAFETY: By C API contract `ptr` is the pointer we passed when
82+
// queuing the timer, so it is a `HrTimer<T>` embedded in a `T`.
83+
let data_ptr = unsafe { T::timer_container_of(timer_ptr) };
84+
85+
// SAFETY:
86+
// - `data_ptr` is derived form the pointer to the `T` that was used to
87+
// queue the timer.
88+
// - As per the safety requirements of the trait `HrTimerHandle`, the
89+
// `ArcHrTimerHandle` associated with this timer is guaranteed to
90+
// be alive until this method returns. That handle borrows the `T`
91+
// behind `data_ptr` thus guaranteeing the validity of
92+
// the `ArcBorrow` created below.
93+
// - We own one refcount in the `ArcTimerHandle` associated with this
94+
// timer, so it is not possible to get a `UniqueArc` to this
95+
// allocation from other `Arc` clones.
96+
let receiver = unsafe { ArcBorrow::from_raw(data_ptr) };
97+
98+
T::run(receiver);
99+
100+
bindings::hrtimer_restart_HRTIMER_NORESTART
101+
}
102+
}

0 commit comments

Comments
 (0)