Skip to content

Commit a282f75

Browse files
Andreas Hindborgfbq
authored andcommitted
rust: hrtimer: implement HrTimerPointer for Pin<Box<T>>
Allow `Pin<Box<T>>` to be the target of a timer callback. Acked-by: Frederic Weisbecker <[email protected]> Signed-off-by: Andreas Hindborg <[email protected]> Reviewed-by: Lyude Paul <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent c894fb9 commit a282f75

File tree

2 files changed

+112
-0
lines changed

2 files changed

+112
-0
lines changed

rust/kernel/time/hrtimer.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,3 +432,6 @@ mod pin;
432432
pub use pin::PinHrTimerHandle;
433433
mod pin_mut;
434434
pub use pin_mut::PinMutHrTimerHandle;
435+
// `box` is a reserved keyword, so prefix with `t` for timer
436+
mod tbox;
437+
pub use tbox::BoxHrTimerHandle;

rust/kernel/time/hrtimer/tbox.rs

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
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::prelude::*;
10+
use crate::time::Ktime;
11+
use core::mem::ManuallyDrop;
12+
use core::ptr::NonNull;
13+
14+
/// A handle for a [`Box<HasHrTimer<T>>`] returned by a call to
15+
/// [`HrTimerPointer::start`].
16+
pub struct BoxHrTimerHandle<T, A>
17+
where
18+
T: HasHrTimer<T>,
19+
A: crate::alloc::Allocator,
20+
{
21+
pub(crate) inner: NonNull<T>,
22+
_p: core::marker::PhantomData<A>,
23+
}
24+
25+
// SAFETY: We implement drop below, and we cancel the timer in the drop
26+
// implementation.
27+
unsafe impl<T, A> HrTimerHandle for BoxHrTimerHandle<T, A>
28+
where
29+
T: HasHrTimer<T>,
30+
A: crate::alloc::Allocator,
31+
{
32+
fn cancel(&mut self) -> bool {
33+
// SAFETY: As we obtained `self.inner` from a valid reference when we
34+
// created `self`, it must point to a valid `T`.
35+
let timer_ptr = unsafe { <T as HasHrTimer<T>>::raw_get_timer(self.inner.as_ptr()) };
36+
37+
// SAFETY: As `timer_ptr` points into `T` and `T` is valid, `timer_ptr`
38+
// must point to a valid `HrTimer` instance.
39+
unsafe { HrTimer::<T>::raw_cancel(timer_ptr) }
40+
}
41+
}
42+
43+
impl<T, A> Drop for BoxHrTimerHandle<T, A>
44+
where
45+
T: HasHrTimer<T>,
46+
A: crate::alloc::Allocator,
47+
{
48+
fn drop(&mut self) {
49+
self.cancel();
50+
// SAFETY: `self.inner` came from a `Box::into_raw` call
51+
drop(unsafe { Box::<T, A>::from_raw(self.inner.as_ptr()) })
52+
}
53+
}
54+
55+
impl<T, A> HrTimerPointer for Pin<Box<T, A>>
56+
where
57+
T: 'static,
58+
T: Send + Sync,
59+
T: HasHrTimer<T>,
60+
T: for<'a> HrTimerCallback<Pointer<'a> = Pin<Box<T, A>>>,
61+
Pin<Box<T, A>>: for<'a> RawHrTimerCallback<CallbackTarget<'a> = Pin<&'a T>>,
62+
A: crate::alloc::Allocator,
63+
{
64+
type TimerHandle = BoxHrTimerHandle<T, A>;
65+
66+
fn start(self, expires: Ktime) -> Self::TimerHandle {
67+
// SAFETY:
68+
// - We will not move out of this box during timer callback (we pass an
69+
// immutable reference to the callback).
70+
// - `Box::into_raw` is guaranteed to return a valid pointer.
71+
let inner =
72+
unsafe { NonNull::new_unchecked(Box::into_raw(Pin::into_inner_unchecked(self))) };
73+
74+
// SAFETY:
75+
// - We keep `self` alive by wrapping it in a handle below.
76+
// - Since we generate the pointer passed to `start` from a valid
77+
// reference, it is a valid pointer.
78+
unsafe { T::start(inner.as_ptr(), expires) };
79+
80+
BoxHrTimerHandle {
81+
inner,
82+
_p: core::marker::PhantomData,
83+
}
84+
}
85+
}
86+
87+
impl<T, A> RawHrTimerCallback for Pin<Box<T, A>>
88+
where
89+
T: 'static,
90+
T: HasHrTimer<T>,
91+
T: for<'a> HrTimerCallback<Pointer<'a> = Pin<Box<T, A>>>,
92+
A: crate::alloc::Allocator,
93+
{
94+
type CallbackTarget<'a> = Pin<&'a T>;
95+
96+
unsafe extern "C" fn run(ptr: *mut bindings::hrtimer) -> bindings::hrtimer_restart {
97+
// `HrTimer` is `repr(C)`
98+
let timer_ptr = ptr.cast::<super::HrTimer<T>>();
99+
100+
// SAFETY: By C API contract `ptr` is the pointer we passed when
101+
// queuing the timer, so it is a `HrTimer<T>` embedded in a `T`.
102+
let data_ptr = unsafe { T::timer_container_of(timer_ptr) };
103+
104+
// SAFETY: We called `Box::into_raw` when we queued the timer.
105+
let tbox = ManuallyDrop::new(Box::into_pin(unsafe { Box::<T, A>::from_raw(data_ptr) }));
106+
107+
T::run(tbox.as_ref()).into_c()
108+
}
109+
}

0 commit comments

Comments
 (0)