8000 rust: hrtimer: introduce hrtimer support · Rust-for-Linux/linux@78e5379 · GitHub
[go: up one dir, main page]

Skip to content

Commit 78e5379

Browse files
committed
rust: hrtimer: introduce hrtimer support
This commit adds support for intrusive use of the hrtimer system. For now, only one timer can be embedded in a host struct. The hrtimer Rust API is based on the intrusive style pattern introduced by the Rust workqueue API. Signed-off-by: Andreas Hindborg <a.hindborg@samsung.com>
1 parent ab883e5 commit 78e5379

File tree

2 files changed

+284
-0
lines changed

2 files changed

+284
-0
lines changed

rust/kernel/hrtimer.rs

Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! Intrusive high resolution timers.
4+
//!
5+
//! Allows scheduling timer callbacks without doing allocations at the time of
6+
//! scheduling. For now, only one timer per type is allowed.
7+
//!
8+
//! # Example
9+
//!
10+
//! ```rust
11+
//! use kernel::{
12+
//! sync::Arc, hrtimer::{RawTimer, Timer, TimerCallback},
13+
//! impl_has_timer, prelude::*, stack_pin_init
14+
//! };
15+
//! use core::sync::atomic::AtomicBool;
16+
//! use core::sync::atomic::Ordering;
17+
//!
18+
//! #[pin_data]
19+
//! struct IntrusiveTimer {
20+
//! #[pin]
21+
//! timer: Timer<Self>,
22+
//! flag: AtomicBool,
23+
//! }
24+
//!
25+
//! impl IntrusiveTimer {
26+
//! fn new() -> impl PinInit<Self> {
27+
//! pin_init!(Self {
28+
//! timer <- Timer::new(),
29+
//! flag: AtomicBool::new(false),
30+
//! })
31+
//! }
32+
//! }
33+
//!
34+
//! impl TimerCallback for IntrusiveTimer {
35+
//! type Receiver = Arc<IntrusiveTimer>;
36+
//!
37+
//! fn run(this: Self::Receiver) {
38+
//! pr_info!("Timer called\n");
39+
//! this.flag.store(true, Ordering::Relaxed);
40+
//! }
41+
//! }
42+
//!
43+
//! impl_has_timer! {
44+
//! impl HasTimer<Self> for IntrusiveTimer { self.timer }
45+
//! }
46+
//!
47+
//! let has_timer = Arc::pin_init(IntrusiveTimer::new())?;
48+
//! has_timer.clone().schedule(200_000_000);
49+
//! while !has_timer.flag.load(Ordering::Relaxed) { core::hint::spin_loop() }
50+
//!
51+
//! pr_info!("Flag raised\n");
52+
//!
53+
//! # Ok::<(), kernel::error::Error>(())
54+
//! ```
55+
//!
56+
//! C header: [`include/linux/hrtimer.h`](srctree/include/linux/hrtimer.h)
57+
58+
use core::{marker::PhantomData, pin::Pin};
59+
60+
use crate::{init::PinInit, prelude::*, sync::Arc, types::Opaque};
61+
62+
/// A timer backed by a C `struct hrtimer`
63+
///
64+
/// # Invariants
65+
///
66+
/// * `self.timer` is initialized by `bindings::hrtimer_init`.
67+
#[repr(transparent)]
68+
#[pin_data(PinnedDrop)]
69+
pub struct Timer<T> {
70+
#[pin]
71+
timer: Opaque<bindings::hrtimer>,
72+
_t: PhantomData<T>,
73+
}
74+
75+
// SAFETY: A `Timer` can be moved to other threads and used from there.
76+
unsafe impl<T> Send for Timer<T> {}
77+
78+
// SAFETY: Timer operations are locked on C side, so it is safe to operate on a
79+
// timer from multiple threads
80+
unsafe impl<T> Sync for Timer<T> {}
81+
82+
impl<T: TimerCallback> Timer<T> {
83+
/// Return an initializer for a new timer instance.
84+
pub fn new() -> impl PinInit<Self> {
85+
crate::pin_init!( Self {
86+
timer <- Opaque::ffi_init(move |place: *mut bindings::hrtimer| {
87+
// SAFETY: By design of `pin_init!`, `place` is a pointer live
88+
// allocation. hrtimer_init will initialize `place` and does not
89+
// require `place` to be initialized prior to the call.
90+
unsafe {
91+
bindings::hrtimer_init(
92+
place,
93+
bindings::CLOCK_MONOTONIC as i32,
94+
bindings::hrtimer_mode_HRTIMER_MODE_REL,
95+
);
96+
}
97+
98+
// SAFETY: `place` is pointing to a live allocation, so the deref
99+
// is safe. The `function` field might not be initialized, but
100+
// `addr_of_mut` does not create a reference to the field.
101+
let function: *mut Option<_> = unsafe { core::ptr::addr_of_mut!((*place).function) };
102+
103+
// SAFETY: `function` points to a valid allocation.
104+
unsafe { core::ptr::write(function, Some(T::Receiver::run)) };
105+
}),
106+
_t: PhantomData,
107+
})
108+
}
109+
}
110+
111+
#[pinned_drop]
112+
impl<T> PinnedDrop for Timer<T> {
113+
fn drop(self: Pin<&mut Self>) {
114+
// SAFETY: By struct invariant `self.timer` was initialized by
115+
// `hrtimer_init` so by C API contract it is safe to call
116+
// `hrtimer_cancel`.
117+
unsafe {
118+
bindings::hrtimer_cancel(self.timer.get());
119+
}
120+
}
121+
}
122+
123+
/// Implemented by pointer types to structs that embed a [`Timer`]. This trait
124+
/// facilitates queueing the timer through the pointer that implements the
125+
/// trait.
126+
///
127+
/// Typical implementers would be [`Box<T>`], [`Arc<T>`], [`ARef<T>`] where `T`
128+
/// has a field of type `Timer`.
129+
///
130+
/// Target must be [`Sync`] because timer callbacks happen in another thread of
131+
/// execution.
132+
///
133+
/// [`Box<T>`]: Box
134+
/// [`Arc<T>`]: Arc
135+
/// [`ARef<T>`]: crate::types::ARef
136+
pub trait RawTimer: Sync {
137+
/// Schedule the timer after `expires` time units
138+
fn schedule(self, expires: u64);
139+
}
140+
141+
/// Implemented by structs that contain timer nodes.
142+
///
143+
/// Clients of the timer API would usually safely implement this trait by using
144+
/// the [`impl_has_timer`] macro.
145+
///
146+
/// # Safety
147+
///
148+
/// Implementers of this trait must ensure that the implementer has a [`Timer`]
149+
/// field at the offset specified by `OFFSET` and that all trait methods are
150+
/// implemented according to their documentation.
151+
///
152+
/// [`impl_has_timer`]: crate::impl_has_timer
153+
pub unsafe trait HasTimer<T> {
154+
/// Offset of the [`Timer`] field within `Self`
155+
const OFFSET: usize;
156+
157+
/// Return a pointer to the [`Timer`] within `Self`.
158+
///
159+
/// # Safety
160+
///
161+
/// `ptr` must point to a valid struct of type `Self`.
162+
unsafe fn raw_get_timer(ptr: *const Self) -> *const Timer<T> {
163+
// SAFETY: By the safety requirement of this trait, the trait
164+
// implementor will have a `Timer` field at the specified offset.
165+
unsafe { ptr.cast::<u8>().add(Self::OFFSET).cast::<Timer<T>>() }
166+
}
167+
168+
/// Return a pointer to the struct that is embedding the [`Timer`] pointed
169+
/// to by `ptr`.
170+
///
171+
/// # Safety
172+
///
173+
/// `ptr` must point to a [`Timer<T>`] field in a struct of type `Self`.
174+
unsafe fn timer_container_of(ptr: *mut Timer<T>) -> *mut Self
175+
where
176+
Self: Sized,
177+
{
178+
// SAFETY: By the safety requirement of this trait, the trait
179+
// implementor will have a `Timer` field at the specified offset.
180+
unsafe { ptr.cast::<u8>().sub(Self::OFFSET).cast::<Self>() }
181+
}
182+
}
183+
184+
/// Implemented by pointer types that can be the target of a C timer callback.
185+
pub trait RawTimerCallback: RawTimer {
186+
/// Callback to be called from C.
187+
///
188+
/// # Safety
189+
///
190+
/// Only to be called by C code in `hrtimer`subsystem.
191+
unsafe extern "C" fn run(ptr: *mut bindings::hrtimer) -> bindings::hrtimer_restart;
192+
}
193+
194+
/// Implemented by pointers to structs that can the target of a timer callback
195+
pub trait TimerCallback {
196+
/// Type of `this` argument for `run()`.
197+
type Receiver: RawTimerCallback;
198+
199+
/// Called by the timer logic when the timer fires
200+
fn run(this: Self::Receiver);
201+
}
202+
203+
impl<T> RawTimer for Arc<T>
204+
where
205+
T: Send + Sync,
206+
T: HasTimer<T>,
207+
{
208+
fn schedule(self, expires: u64) {
209+
let self_ptr = Arc::into_raw(self);
210+
211+
// SAFETY: `self_ptr` is a valid pointer to a `T`
212+
let timer_ptr = unsafe { T::raw_get_timer(self_ptr) };
213+
214+
// `Timer` is `repr(transparent)`
215+
let c_timer_ptr = timer_ptr.cast::<bindings::hrtimer>();
216+
217+
// Schedule the timer - if it is already scheduled it is removed and
218+
// inserted
219+
220+
// SAFETY: c_timer_ptr points to a valid hrtimer instance that was
221+
// initialized by `hrtimer_init`
222+
unsafe {
223+
bindings::hrtimer_start_range_ns(
224+
c_timer_ptr.cast_mut(),
225+
expires as i64,
226+
0,
227+
bindings::hrtimer_mode_HRTIMER_MODE_REL,
228+
);
229+
}
230+
}
231+
}
232+
233+
impl<T> kernel::hrtimer::RawTimerCallback for Arc<T>
234+
where
235+
T: Send + Sync,
236+
T: HasTimer<T>,
237+
T: TimerCallback<Receiver = Self>,
238+
{
239+
unsafe extern "C" fn run(ptr: *mut bindings::hrtimer) -> bindings::hrtimer_restart {
240+
// `Timer` is `repr(transparent)`
241+
let timer_ptr = ptr.cast::<kernel::hrtimer::Timer<T>>();
242+
243+
// SAFETY: By C API contract `ptr` is the pointer we passed when
244+
// enqueing the timer, so it is a `Timer<T>` embedded in a `T`
245+
let data_ptr = unsafe { T::timer_container_of(timer_ptr) };
246+
247+
// SAFETY: This `Arc` comes from a call to `Arc::into_raw()`
248+
let receiver = unsafe { Arc::from_raw(data_ptr) };
249+
250+
T::run(receiver);
251+
252+
bindings::hrtimer_restart_HRTIMER_NORESTART
253+
}
254+
}
255+
256+
/// Use to implement the [`HasTimer<T>`] trait.
257+
///
258+
/// See [`module`] documentation for an example.
259+
///
260+
/// [`module`]: crate::hrtimer
261+
#[macro_export]
262+
macro_rules! impl_has_timer {
263+
($(impl$(<$($implarg:ident),*>)?
264+
HasTimer<$timer_type:ty $(, $id:tt)?>
265+
for $self:ident $(<$($selfarg:ident),*>)?
266+
{ self.$field:ident }
267+
)*) => {$(
268+
// SAFETY: This implementation of `raw_get_timer` only compiles if the
269+
// field has the right type.
270+
unsafe impl$(<$($implarg),*>)? $crate::hrtimer::HasTimer<$timer_type> for $self $(<$($selfarg),*>)? {
271+
const OFFSET: usize = ::core::mem::offset_of!(Self, $field) as usize;
272+
273+
#[inline]
274+
unsafe fn raw_get_timer(ptr: *const Self) -> *const $crate::hrtimer::Timer<$timer_type $(, $id)?> {
275+
// SAFETY: The caller promises that the pointer is not dangling.
276+
unsafe {
277+
::core::ptr::addr_of!((*ptr).$field)
278+
}
279+
}
280+
281+
}
282+
)*};
283+
}

rust/kernel/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ mod allocator;
3737
mod build_assert;
3838
pub mod error;
3939
pub mod folio;
40+
pub mod hrtimer;
4041
pub mod init;
4142
pub mod ioctl;
4243
#[cfg(CONFIG_KUNIT)]

0 commit comments

Comments
 (0)
0