Commit 77580e80 authored by Miguel Ojeda's avatar Miguel Ojeda
Browse files

Merge tag 'rust-timekeeping-for-v6.17' of https://github.com/Rust-for-Linux/linux into rust-next

Pull timekeeping updates from Andreas Hindborg:

 - Make 'Instant' generic over clock source. This allows the compiler to
   assert that arithmetic expressions involving the 'Instant' use
   'Instants' based on the same clock source.

 - Make 'HrTimer' generic over the timer mode. 'HrTimer' timers take a
   'Duration' or an 'Instant' when setting the expiry time, depending on
   the timer mode. With this change, the compiler can check the type
   matches the timer mode.

 - Add an abstraction for 'fsleep'. 'fsleep' is a flexible sleep
   function that will select an appropriate sleep method depending on
   the requested sleep time.

 - Avoid 64-bit divisions on 32-bit hardware when calculating
   timestamps.

 - Seal the 'HrTimerMode' trait. This prevents users of the
   'HrTimerMode' from implementing the trait on their own types.

* tag 'rust-timekeeping-for-v6.17' of https://github.com/Rust-for-Linux/linux:
  rust: time: Add wrapper for fsleep() function
  rust: time: Seal the HrTimerMode trait
  rust: time: Remove Ktime in hrtimer
  rust: time: Make HasHrTimer generic over HrTimerMode
  rust: time: Add HrTimerExpires trait
  rust: time: Replace HrTimerMode enum with trait-based mode types
  rust: time: Add ktime_get() to ClockSource trait
  rust: time: Make Instant generic over ClockSource
  rust: time: Replace ClockId enum with ClockSource trait
  rust: time: Avoid 64-bit integer division on 32-bit architectures
parents 8ecb65b7 d4b29ddf
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@
#include "spinlock.c"
#include "sync.c"
#include "task.c"
#include "time.c"
#include "uaccess.c"
#include "vmalloc.c"
#include "wait.c"

rust/helpers/time.c

0 → 100644
+35 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0

#include <linux/delay.h>
#include <linux/ktime.h>
#include <linux/timekeeping.h>

void rust_helper_fsleep(unsigned long usecs)
{
	fsleep(usecs);
}

ktime_t rust_helper_ktime_get_real(void)
{
	return ktime_get_real();
}

ktime_t rust_helper_ktime_get_boottime(void)
{
	return ktime_get_boottime();
}

ktime_t rust_helper_ktime_get_clocktai(void)
{
	return ktime_get_clocktai();
}

s64 rust_helper_ktime_to_us(const ktime_t kt)
{
	return ktime_to_us(kt);
}

s64 rust_helper_ktime_to_ms(const ktime_t kt)
{
	return ktime_to_ms(kt);
}
+154 −79
Original line number Diff line number Diff line
@@ -24,6 +24,9 @@
//! C header: [`include/linux/jiffies.h`](srctree/include/linux/jiffies.h).
//! C header: [`include/linux/ktime.h`](srctree/include/linux/ktime.h).

use core::marker::PhantomData;

pub mod delay;
pub mod hrtimer;

/// The number of nanoseconds per microsecond.
@@ -49,59 +52,47 @@ pub fn msecs_to_jiffies(msecs: Msecs) -> Jiffies {
    unsafe { bindings::__msecs_to_jiffies(msecs) }
}

/// A specific point in time.
/// Trait for clock sources.
///
/// # Invariants
/// Selection of the clock source depends on the use case. In some cases the usage of a
/// particular clock is mandatory, e.g. in network protocols, filesystems. In other
/// cases the user of the clock has to decide which clock is best suited for the
/// purpose. In most scenarios clock [`Monotonic`] is the best choice as it
/// provides a accurate monotonic notion of time (leap second smearing ignored).
pub trait ClockSource {
    /// The kernel clock ID associated with this clock source.
    ///
/// The `inner` value is in the range from 0 to `KTIME_MAX`.
#[repr(transparent)]
#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord)]
pub struct Instant {
    inner: bindings::ktime_t,
}
    /// This constant corresponds to the C side `clockid_t` value.
    const ID: bindings::clockid_t;

impl Instant {
    /// Get the current time using `CLOCK_MONOTONIC`.
    #[inline]
    pub fn now() -> Self {
        // INVARIANT: The `ktime_get()` function returns a value in the range
        // from 0 to `KTIME_MAX`.
        Self {
            // SAFETY: It is always safe to call `ktime_get()` outside of NMI context.
            inner: unsafe { bindings::ktime_get() },
        }
    /// Get the current time from the clock source.
    ///
    /// The function must return a value in the range from 0 to `KTIME_MAX`.
    fn ktime_get() -> bindings::ktime_t;
}

    /// Return the amount of time elapsed since the [`Instant`].
    #[inline]
    pub fn elapsed(&self) -> Delta {
        Self::now() - *self
    }
}
/// A monotonically increasing clock.
///
/// A nonsettable system-wide clock that represents monotonic time since as
/// described by POSIX, "some unspecified point in the past". On Linux, that
/// point corresponds to the number of seconds that the system has been
/// running since it was booted.
///
/// The CLOCK_MONOTONIC clock is not affected by discontinuous jumps in the
/// CLOCK_REAL (e.g., if the system administrator manually changes the
/// clock), but is affected by frequency adjustments. This clock does not
/// count time that the system is suspended.
pub struct Monotonic;

impl core::ops::Sub for Instant {
    type Output = Delta;
impl ClockSource for Monotonic {
    const ID: bindings::clockid_t = bindings::CLOCK_MONOTONIC as bindings::clockid_t;

    // By the type invariant, it never overflows.
    #[inline]
    fn sub(self, other: Instant) -> Delta {
        Delta {
            nanos: self.inner - other.inner,
        }
    fn ktime_get() -> bindings::ktime_t {
        // SAFETY: It is always safe to call `ktime_get()` outside of NMI context.
        unsafe { bindings::ktime_get() }
    }
}

/// An identifier for a clock. Used when specifying clock sources.
///
///
/// Selection of the clock depends on the use case. In some cases the usage of a
/// particular clock is mandatory, e.g. in network protocols, filesystems.In other
/// cases the user of the clock has to decide which clock is best suited for the
/// purpose. In most scenarios clock [`ClockId::Monotonic`] is the best choice as it
/// provides a accurate monotonic notion of time (leap second smearing ignored).
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[repr(u32)]
pub enum ClockId {
/// A settable system-wide clock that measures real (i.e., wall-clock) time.
///
/// Setting this clock requires appropriate privileges. This clock is
@@ -116,19 +107,17 @@ pub enum ClockId {
/// or slow down the clock to account for the leap second without
/// discontinuities in the clock. If leap second smearing is not applied,
/// the clock will experience discontinuity around leap second adjustment.
    RealTime = bindings::CLOCK_REALTIME,
    /// A monotonically increasing clock.
    ///
    /// A nonsettable system-wide clock that represents monotonic time since—as
    /// described by POSIX—"some unspecified point in the past". On Linux, that
    /// point corresponds to the number of seconds that the system has been
    /// running since it was booted.
    ///
    /// The CLOCK_MONOTONIC clock is not affected by discontinuous jumps in the
    /// CLOCK_REAL (e.g., if the system administrator manually changes the
    /// clock), but is affected by frequency adjustments. This clock does not
    /// count time that the system is suspended.
    Monotonic = bindings::CLOCK_MONOTONIC,
pub struct RealTime;

impl ClockSource for RealTime {
    const ID: bindings::clockid_t = bindings::CLOCK_REALTIME as bindings::clockid_t;

    fn ktime_get() -> bindings::ktime_t {
        // SAFETY: It is always safe to call `ktime_get_real()` outside of NMI context.
        unsafe { bindings::ktime_get_real() }
    }
}

/// A monotonic that ticks while system is suspended.
///
/// A nonsettable system-wide clock that is identical to CLOCK_MONOTONIC,
@@ -136,7 +125,17 @@ pub enum ClockId {
/// allows applications to get a suspend-aware monotonic clock without
/// having to deal with the complications of CLOCK_REALTIME, which may have
/// discontinuities if the time is changed using settimeofday(2) or similar.
    BootTime = bindings::CLOCK_BOOTTIME,
pub struct BootTime;

impl ClockSource for BootTime {
    const ID: bindings::clockid_t = bindings::CLOCK_BOOTTIME as bindings::clockid_t;

    fn ktime_get() -> bindings::ktime_t {
        // SAFETY: It is always safe to call `ktime_get_boottime()` outside of NMI context.
        unsafe { bindings::ktime_get_boottime() }
    }
}

/// International Atomic Time.
///
/// A system-wide clock derived from wall-clock time but counting leap seconds.
@@ -148,12 +147,70 @@ pub enum ClockId {
/// smearing, this clock will not be precise during leap second smearing.
///
/// The acronym TAI refers to International Atomic Time.
    TAI = bindings::CLOCK_TAI,
pub struct Tai;

impl ClockSource for Tai {
    const ID: bindings::clockid_t = bindings::CLOCK_TAI as bindings::clockid_t;

    fn ktime_get() -> bindings::ktime_t {
        // SAFETY: It is always safe to call `ktime_get_tai()` outside of NMI context.
        unsafe { bindings::ktime_get_clocktai() }
    }
}

/// A specific point in time.
///
/// # Invariants
///
/// The `inner` value is in the range from 0 to `KTIME_MAX`.
#[repr(transparent)]
#[derive(PartialEq, PartialOrd, Eq, Ord)]
pub struct Instant<C: ClockSource> {
    inner: bindings::ktime_t,
    _c: PhantomData<C>,
}

impl<C: ClockSource> Clone for Instant<C> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<C: ClockSource> Copy for Instant<C> {}

impl<C: ClockSource> Instant<C> {
    /// Get the current time from the clock source.
    #[inline]
    pub fn now() -> Self {
        // INVARIANT: The `ClockSource::ktime_get()` function returns a value in the range
        // from 0 to `KTIME_MAX`.
        Self {
            inner: C::ktime_get(),
            _c: PhantomData,
        }
    }

    /// Return the amount of time elapsed since the [`Instant`].
    #[inline]
    pub fn elapsed(&self) -> Delta {
        Self::now() - *self
    }

impl ClockId {
    fn into_c(self) -> bindings::clockid_t {
        self as bindings::clockid_t
    #[inline]
    pub(crate) fn as_nanos(&self) -> i64 {
        self.inner
    }
}

impl<C: ClockSource> core::ops::Sub for Instant<C> {
    type Output = Delta;

    // By the type invariant, it never overflows.
    #[inline]
    fn sub(self, other: Instant<C>) -> Delta {
        Delta {
            nanos: self.inner - other.inner,
        }
    }
}

@@ -228,13 +285,31 @@ pub const fn as_nanos(self) -> i64 {
    /// Return the smallest number of microseconds greater than or equal
    /// to the value in the [`Delta`].
    #[inline]
    pub const fn as_micros_ceil(self) -> i64 {
    pub fn as_micros_ceil(self) -> i64 {
        #[cfg(CONFIG_64BIT)]
        {
            self.as_nanos().saturating_add(NSEC_PER_USEC - 1) / NSEC_PER_USEC
        }

        #[cfg(not(CONFIG_64BIT))]
        // SAFETY: It is always safe to call `ktime_to_us()` with any value.
        unsafe {
            bindings::ktime_to_us(self.as_nanos().saturating_add(NSEC_PER_USEC - 1))
        }
    }

    /// Return the number of milliseconds in the [`Delta`].
    #[inline]
    pub const fn as_millis(self) -> i64 {
    pub fn as_millis(self) -> i64 {
        #[cfg(CONFIG_64BIT)]
        {
            self.as_nanos() / NSEC_PER_MSEC
        }

        #[cfg(not(CONFIG_64BIT))]
        // SAFETY: It is always safe to call `ktime_to_ms()` with any value.
        unsafe {
            bindings::ktime_to_ms(self.as_nanos())
        }
    }
}
+49 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0

//! Delay and sleep primitives.
//!
//! This module contains the kernel APIs related to delay and sleep that
//! have been ported or wrapped for usage by Rust code in the kernel.
//!
//! C header: [`include/linux/delay.h`](srctree/include/linux/delay.h).

use super::Delta;
use crate::prelude::*;

/// Sleeps for a given duration at least.
///
/// Equivalent to the C side [`fsleep()`], flexible sleep function,
/// which automatically chooses the best sleep method based on a duration.
///
/// `delta` must be within `[0, i32::MAX]` microseconds;
/// otherwise, it is erroneous behavior. That is, it is considered a bug
/// to call this function with an out-of-range value, in which case the function
/// will sleep for at least the maximum value in the range and may warn
/// in the future.
///
/// The behavior above differs from the C side [`fsleep()`] for which out-of-range
/// values mean "infinite timeout" instead.
///
/// This function can only be used in a nonatomic context.
///
/// [`fsleep()`]: https://docs.kernel.org/timers/delay_sleep_functions.html#c.fsleep
pub fn fsleep(delta: Delta) {
    // The maximum value is set to `i32::MAX` microseconds to prevent integer
    // overflow inside fsleep, which could lead to unintentional infinite sleep.
    const MAX_DELTA: Delta = Delta::from_micros(i32::MAX as i64);

    let delta = if (Delta::ZERO..=MAX_DELTA).contains(&delta) {
        delta
    } else {
        // TODO: Add WARN_ONCE() when it's supported.
        MAX_DELTA
    };

    // SAFETY: It is always safe to call `fsleep()` with any duration.
    unsafe {
        // Convert the duration to microseconds and round up to preserve
        // the guarantee; `fsleep()` sleeps for at least the provided duration,
        // but that it may sleep for longer under some circumstances.
        bindings::fsleep(delta.as_micros_ceil() as c_ulong)
    }
}
+203 −99

File changed.

Preview size limit exceeded, changes collapsed.

Loading