Skip to content

Commit cfe872e

Browse files
committed
Merge tag 'rust-timekeeping-v6.18' of https://github.com/Rust-for-Linux/linux into rust-next
Pull timekeeping updates from Andreas Hindborg: - Add methods on 'HrTimer' that can only be called with exclusive access to an unarmed timer, or form timer callback context. - Add arithmetic operations to 'Instant' and 'Delta'. - Add a few convenience and access methods to 'HrTimer' and 'Instant'. * tag 'rust-timekeeping-v6.18' of https://github.com/Rust-for-Linux/linux: rust: time: Implement basic arithmetic operations for Delta rust: time: Implement Add<Delta>/Sub<Delta> for Instant rust: hrtimer: Add HrTimer::expires() rust: time: Add Instant::from_ktime() rust: hrtimer: Add forward_now() to HrTimer and HrTimerCallbackContext rust: hrtimer: Add HrTimerCallbackContext and ::forward() rust: hrtimer: Add HrTimer::raw_forward() and forward() rust: hrtimer: Add HrTimerInstant rust: hrtimer: Document the return value for HrTimerHandle::cancel()
2 parents 9578c39 + 4521438 commit cfe872e

File tree

6 files changed

+344
-10
lines changed

6 files changed

+344
-10
lines changed

rust/kernel/time.rs

Lines changed: 162 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
//! C header: [`include/linux/ktime.h`](srctree/include/linux/ktime.h).
2626
2727
use core::marker::PhantomData;
28+
use core::ops;
2829

2930
pub mod delay;
3031
pub mod hrtimer;
@@ -200,9 +201,31 @@ impl<C: ClockSource> Instant<C> {
200201
pub(crate) fn as_nanos(&self) -> i64 {
201202
self.inner
202203
}
204+
205+
/// Create an [`Instant`] from a `ktime_t` without checking if it is non-negative.
206+
///
207+
/// # Panics
208+
///
209+
/// On debug builds, this function will panic if `ktime` is not in the range from 0 to
210+
/// `KTIME_MAX`.
211+
///
212+
/// # Safety
213+
///
214+
/// The caller promises that `ktime` is in the range from 0 to `KTIME_MAX`.
215+
#[inline]
216+
pub(crate) unsafe fn from_ktime(ktime: bindings::ktime_t) -> Self {
217+
debug_assert!(ktime >= 0);
218+
219+
// INVARIANT: Our safety contract ensures that `ktime` is in the range from 0 to
220+
// `KTIME_MAX`.
221+
Self {
222+
inner: ktime,
223+
_c: PhantomData,
224+
}
225+
}
203226
}
204227

205-
impl<C: ClockSource> core::ops::Sub for Instant<C> {
228+
impl<C: ClockSource> ops::Sub for Instant<C> {
206229
type Output = Delta;
207230

208231
// By the type invariant, it never overflows.
@@ -214,6 +237,46 @@ impl<C: ClockSource> core::ops::Sub for Instant<C> {
214237
}
215238
}
216239

240+
impl<T: ClockSource> ops::Add<Delta> for Instant<T> {
241+
type Output = Self;
242+
243+
#[inline]
244+
fn add(self, rhs: Delta) -> Self::Output {
245+
// INVARIANT: With arithmetic over/underflow checks enabled, this will panic if we overflow
246+
// (e.g. go above `KTIME_MAX`)
247+
let res = self.inner + rhs.nanos;
248+
249+
// INVARIANT: With overflow checks enabled, we verify here that the value is >= 0
250+
#[cfg(CONFIG_RUST_OVERFLOW_CHECKS)]
251+
assert!(res >= 0);
252+
253+
Self {
254+
inner: res,
255+
_c: PhantomData,
256+
}
257+
}
258+
}
259+
260+
impl<T: ClockSource> ops::Sub<Delta> for Instant<T> {
261+
type Output = Self;
262+
263+
#[inline]
264+
fn sub(self, rhs: Delta) -> Self::Output {
265+
// INVARIANT: With arithmetic over/underflow checks enabled, this will panic if we overflow
266+
// (e.g. go above `KTIME_MAX`)
267+
let res = self.inner - rhs.nanos;
268+
269+
// INVARIANT: With overflow checks enabled, we verify here that the value is >= 0
270+
#[cfg(CONFIG_RUST_OVERFLOW_CHECKS)]
271+
assert!(res >= 0);
272+
273+
Self {
274+
inner: res,
275+
_c: PhantomData,
276+
}
277+
}
278+
}
279+
217280
/// A span of time.
218281
///
219282
/// This struct represents a span of time, with its value stored as nanoseconds.
@@ -224,6 +287,78 @@ pub struct Delta {
224287
nanos: i64,
225288
}
226289

290+
impl ops::Add for Delta {
291+
type Output = Self;
292+
293+
#[inline]
294+
fn add(self, rhs: Self) -> Self {
295+
Self {
296+
nanos: self.nanos + rhs.nanos,
297+
}
298+
}
299+
}
300+
301+
impl ops::AddAssign for Delta {
302+
#[inline]
303+
fn add_assign(&mut self, rhs: Self) {
304+
self.nanos += rhs.nanos;
305+
}
306+
}
307+
308+
impl ops::Sub for Delta {
309+
type Output = Self;
310+
311+
#[inline]
312+
fn sub(self, rhs: Self) -> Self::Output {
313+
Self {
314+
nanos: self.nanos - rhs.nanos,
315+
}
316+
}
317+
}
318+
319+
impl ops::SubAssign for Delta {
320+
#[inline]
321+
fn sub_assign(&mut self, rhs: Self) {
322+
self.nanos -= rhs.nanos;
323+
}
324+
}
325+
326+
impl ops::Mul<i64> for Delta {
327+
type Output = Self;
328+
329+
#[inline]
330+
fn mul(self, rhs: i64) -> Self::Output {
331+
Self {
332+
nanos: self.nanos * rhs,
333+
}
334+
}
335+
}
336+
337+
impl ops::MulAssign<i64> for Delta {
338+
#[inline]
339+
fn mul_assign(&mut self, rhs: i64) {
340+
self.nanos *= rhs;
341+
}
342+
}
343+
344+
impl ops::Div for Delta {
345+
type Output = i64;
346+
347+
#[inline]
348+
fn div(self, rhs: Self) -> Self::Output {
349+
#[cfg(CONFIG_64BIT)]
350+
{
351+
self.nanos / rhs.nanos
352+
}
353+
354+
#[cfg(not(CONFIG_64BIT))]
355+
{
356+
// SAFETY: This function is always safe to call regardless of the input values
357+
unsafe { bindings::div64_s64(self.nanos, rhs.nanos) }
358+
}
359+
}
360+
}
361+
227362
impl Delta {
228363
/// A span of time equal to zero.
229364
pub const ZERO: Self = Self { nanos: 0 };
@@ -312,4 +447,30 @@ impl Delta {
312447
bindings::ktime_to_ms(self.as_nanos())
313448
}
314449
}
450+
451+
/// Return `self % dividend` where `dividend` is in nanoseconds.
452+
///
453+
/// The kernel doesn't have any emulation for `s64 % s64` on 32 bit platforms, so this is
454+
/// limited to 32 bit dividends.
455+
#[inline]
456+
pub fn rem_nanos(self, dividend: i32) -> Self {
457+
#[cfg(CONFIG_64BIT)]
458+
{
459+
Self {
460+
nanos: self.as_nanos() % i64::from(dividend),
461+
}
462+
}
463+
464+
#[cfg(not(CONFIG_64BIT))]
465+
{
466+
let mut rem = 0;
467+
468+
// SAFETY: `rem` is in the stack, so we can always provide a valid pointer to it.
469+
unsafe { bindings::div_s64_rem(self.as_nanos(), dividend, &mut rem) };
470+
471+
Self {
472+
nanos: i64::from(rem),
473+
}
474+
}
475+
}
315476
}

rust/kernel/time/hrtimer.rs

Lines changed: 149 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,14 @@
6969
7070
use super::{ClockSource, Delta, Instant};
7171
use crate::{prelude::*, types::Opaque};
72-
use core::marker::PhantomData;
72+
use core::{marker::PhantomData, ptr::NonNull};
7373
use pin_init::PinInit;
7474

75+
/// A type-alias to refer to the [`Instant<C>`] for a given `T` from [`HrTimer<T>`].
76+
///
77+
/// Where `C` is the [`ClockSource`] of the [`HrTimer`].
78+
pub type HrTimerInstant<T> = Instant<<<T as HasHrTimer<T>>::TimerMode as HrTimerMode>::Clock>;
79+
7580
/// A timer backed by a C `struct hrtimer`.
7681
///
7782
/// # Invariants
@@ -163,6 +168,84 @@ impl<T> HrTimer<T> {
163168
// handled on the C side.
164169
unsafe { bindings::hrtimer_cancel(c_timer_ptr) != 0 }
165170
}
171+
172+
/// Forward the timer expiry for a given timer pointer.
173+
///
174+
/// # Safety
175+
///
176+
/// - `self_ptr` must point to a valid `Self`.
177+
/// - The caller must either have exclusive access to the data pointed at by `self_ptr`, or be
178+
/// within the context of the timer callback.
179+
#[inline]
180+
unsafe fn raw_forward(self_ptr: *mut Self, now: HrTimerInstant<T>, interval: Delta) -> u64
181+
where
182+
T: HasHrTimer<T>,
183+
{
184+
// SAFETY:
185+
// * The C API requirements for this function are fulfilled by our safety contract.
186+
// * `self_ptr` is guaranteed to point to a valid `Self` via our safety contract
187+
unsafe {
188+
bindings::hrtimer_forward(Self::raw_get(self_ptr), now.as_nanos(), interval.as_nanos())
189+
}
190+
}
191+
192+
/// Conditionally forward the timer.
193+
///
194+
/// If the timer expires after `now`, this function does nothing and returns 0. If the timer
195+
/// expired at or before `now`, this function forwards the timer by `interval` until the timer
196+
/// expires after `now` and then returns the number of times the timer was forwarded by
197+
/// `interval`.
198+
///
199+
/// This function is mainly useful for timer types which can provide exclusive access to the
200+
/// timer when the timer is not running. For forwarding the timer from within the timer callback
201+
/// context, see [`HrTimerCallbackContext::forward()`].
202+
///
203+
/// Returns the number of overruns that occurred as a result of the timer expiry change.
204+
pub fn forward(self: Pin<&mut Self>, now: HrTimerInstant<T>, interval: Delta) -> u64
205+
where
206+
T: HasHrTimer<T>,
207+
{
208+
// SAFETY: `raw_forward` does not move `Self`
209+
let this = unsafe { self.get_unchecked_mut() };
210+
211+
// SAFETY: By existence of `Pin<&mut Self>`, the pointer passed to `raw_forward` points to a
212+
// valid `Self` that we have exclusive access to.
213+
unsafe { Self::raw_forward(this, now, interval) }
214+
}
215+
216+
/// Conditionally forward the timer.
217+
///
218+
/// This is a variant of [`forward()`](Self::forward) that uses an interval after the current
219+
/// time of the base clock for the [`HrTimer`].
220+
pub fn forward_now(self: Pin<&mut Self>, interval: Delta) -> u64
221+
where
222+
T: HasHrTimer<T>,
223+
{
224+
self.forward(HrTimerInstant::<T>::now(), interval)
225+
}
226+
227+
/// Return the time expiry for this [`HrTimer`].
228+
///
229+
/// This value should only be used as a snapshot, as the actual expiry time could change after
230+
/// this function is called.
231+
pub fn expires(&self) -> HrTimerInstant<T>
232+
where
233+
T: HasHrTimer<T>,
234+
{
235+
// SAFETY: `self` is an immutable reference and thus always points to a valid `HrTimer`.
236+
let c_timer_ptr = unsafe { HrTimer::raw_get(self) };
237+
238+
// SAFETY:
239+
// - Timers cannot have negative ktime_t values as their expiration time.
240+
// - There's no actual locking here, a racy read is fine and expected
241+
unsafe {
242+
Instant::from_ktime(
243+
// This `read_volatile` is intended to correspond to a READ_ONCE call.
244+
// FIXME(read_once): Replace with `read_once` when available on the Rust side.
245+
core::ptr::read_volatile(&raw const ((*c_timer_ptr).node.expires)),
246+
)
247+
}
248+
}
166249
}
167250

168251
/// Implemented by pointer types that point to structs that contain a [`HrTimer`].
@@ -300,9 +383,13 @@ pub trait HrTimerCallback {
300383
type Pointer<'a>: RawHrTimerCallback;
301384

302385
/// Called by the timer logic when the timer fires.
303-
fn run(this: <Self::Pointer<'_> as RawHrTimerCallback>::CallbackTarget<'_>) -> HrTimerRestart
386+
fn run(
387+
this: <Self::Pointer<'_> as RawHrTimerCallback>::CallbackTarget<'_>,
388+
ctx: HrTimerCallbackContext<'_, Self>,
389+
) -> HrTimerRestart
304390
where
305-
Self: Sized;
391+
Self: Sized,
392+
Self: HasHrTimer<Self>;
306393
}
307394

308395
/// A handle representing a potentially running timer.
@@ -324,6 +411,8 @@ pub unsafe trait HrTimerHandle {
324411
/// Note that the timer might be started by a concurrent start operation. If
325412
/// so, the timer might not be in the **stopped** state when this function
326413
/// returns.
414+
///
415+
/// Returns `true` if the timer was running.
327416
fn cancel(&mut self) -> bool;
328417
}
329418

@@ -585,6 +674,63 @@ impl<C: ClockSource> HrTimerMode for RelativePinnedHardMode<C> {
585674
type Expires = Delta;
586675
}
587676

677+
/// Privileged smart-pointer for a [`HrTimer`] callback context.
678+
///
679+
/// Many [`HrTimer`] methods can only be called in two situations:
680+
///
681+
/// * When the caller has exclusive access to the `HrTimer` and the `HrTimer` is guaranteed not to
682+
/// be running.
683+
/// * From within the context of an `HrTimer`'s callback method.
684+
///
685+
/// This type provides access to said methods from within a timer callback context.
686+
///
687+
/// # Invariants
688+
///
689+
/// * The existence of this type means the caller is currently within the callback for an
690+
/// [`HrTimer`].
691+
/// * `self.0` always points to a live instance of [`HrTimer<T>`].
692+
pub struct HrTimerCallbackContext<'a, T: HasHrTimer<T>>(NonNull<HrTimer<T>>, PhantomData<&'a ()>);
693+
694+
impl<'a, T: HasHrTimer<T>> HrTimerCallbackContext<'a, T> {
695+
/// Create a new [`HrTimerCallbackContext`].
696+
///
697+
/// # Safety
698+
///
699+
/// This function relies on the caller being within the context of a timer callback, so it must
700+
/// not be used anywhere except for within implementations of [`RawHrTimerCallback::run`]. The
701+
/// caller promises that `timer` points to a valid initialized instance of
702+
/// [`bindings::hrtimer`].
703+
///
704+
/// The returned `Self` must not outlive the function context of [`RawHrTimerCallback::run`]
705+
/// where this function is called.
706+
pub(crate) unsafe fn from_raw(timer: *mut HrTimer<T>) -> Self {
707+
// SAFETY: The caller guarantees `timer` is a valid pointer to an initialized
708+
// `bindings::hrtimer`
709+
// INVARIANT: Our safety contract ensures that we're within the context of a timer callback
710+
// and that `timer` points to a live instance of `HrTimer<T>`.
711+
Self(unsafe { NonNull::new_unchecked(timer) }, PhantomData)
712+
}
713+
714+
/// Conditionally forward the timer.
715+
///
716+
/// This function is identical to [`HrTimer::forward()`] except that it may only be used from
717+
/// within the context of a [`HrTimer`] callback.
718+
pub fn forward(&mut self, now: HrTimerInstant<T>, interval: Delta) -> u64 {
719+
// SAFETY:
720+
// - We are guaranteed to be within the context of a timer callback by our type invariants
721+
// - By our type invariants, `self.0` always points to a valid `HrTimer<T>`
722+
unsafe { HrTimer::<T>::raw_forward(self.0.as_ptr(), now, interval) }
723+
}
724+
725+
/// Conditionally forward the timer.
726+
///
727+
/// This is a variant of [`HrTimerCallbackContext::forward()`] that uses an interval after the
728+
/// current time of the base clock for the [`HrTimer`].
729+
pub fn forward_now(&mut self, duration: Delta) -> u64 {
730+
self.forward(HrTimerInstant::<T>::now(), duration)
731+
}
732+
}
733+
588734
/// Use to implement the [`HasHrTimer<T>`] trait.
589735
///
590736
/// See [`module`] documentation for an example.

0 commit comments

Comments
 (0)