Skip to content

Commit 77580e8

Browse files
committed
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
2 parents 8ecb65b + d4b29dd commit 77580e8

9 files changed

Lines changed: 466 additions & 186 deletions

File tree

rust/helpers/helpers.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include "spinlock.c"
4242
#include "sync.c"
4343
#include "task.c"
44+
#include "time.c"
4445
#include "uaccess.c"
4546
#include "vmalloc.c"
4647
#include "wait.c"

rust/helpers/time.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <linux/delay.h>
4+
#include <linux/ktime.h>
5+
#include <linux/timekeeping.h>
6+
7+
void rust_helper_fsleep(unsigned long usecs)
8+
{
9+
fsleep(usecs);
10+
}
11+
12+
ktime_t rust_helper_ktime_get_real(void)
13+
{
14+
return ktime_get_real();
15+
}
16+
17+
ktime_t rust_helper_ktime_get_boottime(void)
18+
{
19+
return ktime_get_boottime();
20+
}
21+
22+
ktime_t rust_helper_ktime_get_clocktai(void)
23+
{
24+
return ktime_get_clocktai();
25+
}
26+
27+
s64 rust_helper_ktime_to_us(const ktime_t kt)
28+
{
29+
return ktime_to_us(kt);
30+
}
31+
32+
s64 rust_helper_ktime_to_ms(const ktime_t kt)
33+
{
34+
return ktime_to_ms(kt);
35+
}

rust/kernel/time.rs

Lines changed: 154 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
//! C header: [`include/linux/jiffies.h`](srctree/include/linux/jiffies.h).
2525
//! C header: [`include/linux/ktime.h`](srctree/include/linux/ktime.h).
2626
27+
use core::marker::PhantomData;
28+
29+
pub mod delay;
2730
pub mod hrtimer;
2831

2932
/// The number of nanoseconds per microsecond.
@@ -49,26 +52,141 @@ pub fn msecs_to_jiffies(msecs: Msecs) -> Jiffies {
4952
unsafe { bindings::__msecs_to_jiffies(msecs) }
5053
}
5154

55+
/// Trait for clock sources.
56+
///
57+
/// Selection of the clock source depends on the use case. In some cases the usage of a
58+
/// particular clock is mandatory, e.g. in network protocols, filesystems. In other
59+
/// cases the user of the clock has to decide which clock is best suited for the
60+
/// purpose. In most scenarios clock [`Monotonic`] is the best choice as it
61+
/// provides a accurate monotonic notion of time (leap second smearing ignored).
62+
pub trait ClockSource {
63+
/// The kernel clock ID associated with this clock source.
64+
///
65+
/// This constant corresponds to the C side `clockid_t` value.
66+
const ID: bindings::clockid_t;
67+
68+
/// Get the current time from the clock source.
69+
///
70+
/// The function must return a value in the range from 0 to `KTIME_MAX`.
71+
fn ktime_get() -> bindings::ktime_t;
72+
}
73+
74+
/// A monotonically increasing clock.
75+
///
76+
/// A nonsettable system-wide clock that represents monotonic time since as
77+
/// described by POSIX, "some unspecified point in the past". On Linux, that
78+
/// point corresponds to the number of seconds that the system has been
79+
/// running since it was booted.
80+
///
81+
/// The CLOCK_MONOTONIC clock is not affected by discontinuous jumps in the
82+
/// CLOCK_REAL (e.g., if the system administrator manually changes the
83+
/// clock), but is affected by frequency adjustments. This clock does not
84+
/// count time that the system is suspended.
85+
pub struct Monotonic;
86+
87+
impl ClockSource for Monotonic {
88+
const ID: bindings::clockid_t = bindings::CLOCK_MONOTONIC as bindings::clockid_t;
89+
90+
fn ktime_get() -> bindings::ktime_t {
91+
// SAFETY: It is always safe to call `ktime_get()` outside of NMI context.
92+
unsafe { bindings::ktime_get() }
93+
}
94+
}
95+
96+
/// A settable system-wide clock that measures real (i.e., wall-clock) time.
97+
///
98+
/// Setting this clock requires appropriate privileges. This clock is
99+
/// affected by discontinuous jumps in the system time (e.g., if the system
100+
/// administrator manually changes the clock), and by frequency adjustments
101+
/// performed by NTP and similar applications via adjtime(3), adjtimex(2),
102+
/// clock_adjtime(2), and ntp_adjtime(3). This clock normally counts the
103+
/// number of seconds since 1970-01-01 00:00:00 Coordinated Universal Time
104+
/// (UTC) except that it ignores leap seconds; near a leap second it may be
105+
/// adjusted by leap second smearing to stay roughly in sync with UTC. Leap
106+
/// second smearing applies frequency adjustments to the clock to speed up
107+
/// or slow down the clock to account for the leap second without
108+
/// discontinuities in the clock. If leap second smearing is not applied,
109+
/// the clock will experience discontinuity around leap second adjustment.
110+
pub struct RealTime;
111+
112+
impl ClockSource for RealTime {
113+
const ID: bindings::clockid_t = bindings::CLOCK_REALTIME as bindings::clockid_t;
114+
115+
fn ktime_get() -> bindings::ktime_t {
116+
// SAFETY: It is always safe to call `ktime_get_real()` outside of NMI context.
117+
unsafe { bindings::ktime_get_real() }
118+
}
119+
}
120+
121+
/// A monotonic that ticks while system is suspended.
122+
///
123+
/// A nonsettable system-wide clock that is identical to CLOCK_MONOTONIC,
124+
/// except that it also includes any time that the system is suspended. This
125+
/// allows applications to get a suspend-aware monotonic clock without
126+
/// having to deal with the complications of CLOCK_REALTIME, which may have
127+
/// discontinuities if the time is changed using settimeofday(2) or similar.
128+
pub struct BootTime;
129+
130+
impl ClockSource for BootTime {
131+
const ID: bindings::clockid_t = bindings::CLOCK_BOOTTIME as bindings::clockid_t;
132+
133+
fn ktime_get() -> bindings::ktime_t {
134+
// SAFETY: It is always safe to call `ktime_get_boottime()` outside of NMI context.
135+
unsafe { bindings::ktime_get_boottime() }
136+
}
137+
}
138+
139+
/// International Atomic Time.
140+
///
141+
/// A system-wide clock derived from wall-clock time but counting leap seconds.
142+
///
143+
/// This clock is coupled to CLOCK_REALTIME and will be set when CLOCK_REALTIME is
144+
/// set, or when the offset to CLOCK_REALTIME is changed via adjtimex(2). This
145+
/// usually happens during boot and **should** not happen during normal operations.
146+
/// However, if NTP or another application adjusts CLOCK_REALTIME by leap second
147+
/// smearing, this clock will not be precise during leap second smearing.
148+
///
149+
/// The acronym TAI refers to International Atomic Time.
150+
pub struct Tai;
151+
152+
impl ClockSource for Tai {
153+
const ID: bindings::clockid_t = bindings::CLOCK_TAI as bindings::clockid_t;
154+
155+
fn ktime_get() -> bindings::ktime_t {
156+
// SAFETY: It is always safe to call `ktime_get_tai()` outside of NMI context.
157+
unsafe { bindings::ktime_get_clocktai() }
158+
}
159+
}
160+
52161
/// A specific point in time.
53162
///
54163
/// # Invariants
55164
///
56165
/// The `inner` value is in the range from 0 to `KTIME_MAX`.
57166
#[repr(transparent)]
58-
#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord)]
59-
pub struct Instant {
167+
#[derive(PartialEq, PartialOrd, Eq, Ord)]
168+
pub struct Instant<C: ClockSource> {
60169
inner: bindings::ktime_t,
170+
_c: PhantomData<C>,
171+
}
172+
173+
impl<C: ClockSource> Clone for Instant<C> {
174+
fn clone(&self) -> Self {
175+
*self
176+
}
61177
}
62178

63-
impl Instant {
64-
/// Get the current time using `CLOCK_MONOTONIC`.
179+
impl<C: ClockSource> Copy for Instant<C> {}
180+
181+
impl<C: ClockSource> Instant<C> {
182+
/// Get the current time from the clock source.
65183
#[inline]
66184
pub fn now() -> Self {
67-
// INVARIANT: The `ktime_get()` function returns a value in the range
185+
// INVARIANT: The `ClockSource::ktime_get()` function returns a value in the range
68186
// from 0 to `KTIME_MAX`.
69187
Self {
70-
// SAFETY: It is always safe to call `ktime_get()` outside of NMI context.
71-
inner: unsafe { bindings::ktime_get() },
188+
inner: C::ktime_get(),
189+
_c: PhantomData,
72190
}
73191
}
74192

@@ -77,86 +195,25 @@ impl Instant {
77195
pub fn elapsed(&self) -> Delta {
78196
Self::now() - *self
79197
}
198+
199+
#[inline]
200+
pub(crate) fn as_nanos(&self) -> i64 {
201+
self.inner
202+
}
80203
}
81204

82-
impl core::ops::Sub for Instant {
205+
impl<C: ClockSource> core::ops::Sub for Instant<C> {
83206
type Output = Delta;
84207

85208
// By the type invariant, it never overflows.
86209
#[inline]
87-
fn sub(self, other: Instant) -> Delta {
210+
fn sub(self, other: Instant<C>) -> Delta {
88211
Delta {
89212
nanos: self.inner - other.inner,
90213
}
91214
}
92215
}
93216

94-
/// An identifier for a clock. Used when specifying clock sources.
95-
///
96-
///
97-
/// Selection of the clock depends on the use case. In some cases the usage of a
98-
/// particular clock is mandatory, e.g. in network protocols, filesystems.In other
99-
/// cases the user of the clock has to decide which clock is best suited for the
100-
/// purpose. In most scenarios clock [`ClockId::Monotonic`] is the best choice as it
101-
/// provides a accurate monotonic notion of time (leap second smearing ignored).
102-
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
103-
#[repr(u32)]
104-
pub enum ClockId {
105-
/// A settable system-wide clock that measures real (i.e., wall-clock) time.
106-
///
107-
/// Setting this clock requires appropriate privileges. This clock is
108-
/// affected by discontinuous jumps in the system time (e.g., if the system
109-
/// administrator manually changes the clock), and by frequency adjustments
110-
/// performed by NTP and similar applications via adjtime(3), adjtimex(2),
111-
/// clock_adjtime(2), and ntp_adjtime(3). This clock normally counts the
112-
/// number of seconds since 1970-01-01 00:00:00 Coordinated Universal Time
113-
/// (UTC) except that it ignores leap seconds; near a leap second it may be
114-
/// adjusted by leap second smearing to stay roughly in sync with UTC. Leap
115-
/// second smearing applies frequency adjustments to the clock to speed up
116-
/// or slow down the clock to account for the leap second without
117-
/// discontinuities in the clock. If leap second smearing is not applied,
118-
/// the clock will experience discontinuity around leap second adjustment.
119-
RealTime = bindings::CLOCK_REALTIME,
120-
/// A monotonically increasing clock.
121-
///
122-
/// A nonsettable system-wide clock that represents monotonic time since—as
123-
/// described by POSIX—"some unspecified point in the past". On Linux, that
124-
/// point corresponds to the number of seconds that the system has been
125-
/// running since it was booted.
126-
///
127-
/// The CLOCK_MONOTONIC clock is not affected by discontinuous jumps in the
128-
/// CLOCK_REAL (e.g., if the system administrator manually changes the
129-
/// clock), but is affected by frequency adjustments. This clock does not
130-
/// count time that the system is suspended.
131-
Monotonic = bindings::CLOCK_MONOTONIC,
132-
/// A monotonic that ticks while system is suspended.
133-
///
134-
/// A nonsettable system-wide clock that is identical to CLOCK_MONOTONIC,
135-
/// except that it also includes any time that the system is suspended. This
136-
/// allows applications to get a suspend-aware monotonic clock without
137-
/// having to deal with the complications of CLOCK_REALTIME, which may have
138-
/// discontinuities if the time is changed using settimeofday(2) or similar.
139-
BootTime = bindings::CLOCK_BOOTTIME,
140-
/// International Atomic Time.
141-
///
142-
/// A system-wide clock derived from wall-clock time but counting leap seconds.
143-
///
144-
/// This clock is coupled to CLOCK_REALTIME and will be set when CLOCK_REALTIME is
145-
/// set, or when the offset to CLOCK_REALTIME is changed via adjtimex(2). This
146-
/// usually happens during boot and **should** not happen during normal operations.
147-
/// However, if NTP or another application adjusts CLOCK_REALTIME by leap second
148-
/// smearing, this clock will not be precise during leap second smearing.
149-
///
150-
/// The acronym TAI refers to International Atomic Time.
151-
TAI = bindings::CLOCK_TAI,
152-
}
153-
154-
impl ClockId {
155-
fn into_c(self) -> bindings::clockid_t {
156-
self as bindings::clockid_t
157-
}
158-
}
159-
160217
/// A span of time.
161218
///
162219
/// This struct represents a span of time, with its value stored as nanoseconds.
@@ -228,13 +285,31 @@ impl Delta {
228285
/// Return the smallest number of microseconds greater than or equal
229286
/// to the value in the [`Delta`].
230287
#[inline]
231-
pub const fn as_micros_ceil(self) -> i64 {
232-
self.as_nanos().saturating_add(NSEC_PER_USEC - 1) / NSEC_PER_USEC
288+
pub fn as_micros_ceil(self) -> i64 {
289+
#[cfg(CONFIG_64BIT)]
290+
{
291+
self.as_nanos().saturating_add(NSEC_PER_USEC - 1) / NSEC_PER_USEC
292+
}
293+
294+
#[cfg(not(CONFIG_64BIT))]
295+
// SAFETY: It is always safe to call `ktime_to_us()` with any value.
296+
unsafe {
297+
bindings::ktime_to_us(self.as_nanos().saturating_add(NSEC_PER_USEC - 1))
298+
}
233299
}
234300

235301
/// Return the number of milliseconds in the [`Delta`].
236302
#[inline]
237-
pub const fn as_millis(self) -> i64 {
238-
self.as_nanos() / NSEC_PER_MSEC
303+
pub fn as_millis(self) -> i64 {
304+
#[cfg(CONFIG_64BIT)]
305+
{
306+
self.as_nanos() / NSEC_PER_MSEC
307+
}
308+
309+
#[cfg(not(CONFIG_64BIT))]
310+
// SAFETY: It is always safe to call `ktime_to_ms()` with any value.
311+
unsafe {
312+
bindings::ktime_to_ms(self.as_nanos())
313+
}
239314
}
240315
}

rust/kernel/time/delay.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! Delay and sleep primitives.
4+
//!
5+
//! This module contains the kernel APIs related to delay and sleep that
6+
//! have been ported or wrapped for usage by Rust code in the kernel.
7+
//!
8+
//! C header: [`include/linux/delay.h`](srctree/include/linux/delay.h).
9+
10+
use super::Delta;
11+
use crate::prelude::*;
12+
13+
/// Sleeps for a given duration at least.
14+
///
15+
/// Equivalent to the C side [`fsleep()`], flexible sleep function,
16+
/// which automatically chooses the best sleep method based on a duration.
17+
///
18+
/// `delta` must be within `[0, i32::MAX]` microseconds;
19+
/// otherwise, it is erroneous behavior. That is, it is considered a bug
20+
/// to call this function with an out-of-range value, in which case the function
21+
/// will sleep for at least the maximum value in the range and may warn
22+
/// in the future.
23+
///
24+
/// The behavior above differs from the C side [`fsleep()`] for which out-of-range
25+
/// values mean "infinite timeout" instead.
26+
///
27+
/// This function can only be used in a nonatomic context.
28+
///
29+
/// [`fsleep()`]: https://docs.kernel.org/timers/delay_sleep_functions.html#c.fsleep
30+
pub fn fsleep(delta: Delta) {
31+
// The maximum value is set to `i32::MAX` microseconds to prevent integer
32+
// overflow inside fsleep, which could lead to unintentional infinite sleep.
33+
const MAX_DELTA: Delta = Delta::from_micros(i32::MAX as i64);
34+
35+
let delta = if (Delta::ZERO..=MAX_DELTA).contains(&delta) {
36+
delta
37+
} else {
38+
// TODO: Add WARN_ONCE() when it's supported.
39+
MAX_DELTA
40+
};
41+
42+
// SAFETY: It is always safe to call `fsleep()` with any duration.
43+
unsafe {
44+
// Convert the duration to microseconds and round up to preserve
45+
// the guarantee; `fsleep()` sleeps for at least the provided duration,
46+
// but that it may sleep for longer under some circumstances.
47+
bindings::fsleep(delta.as_micros_ceil() as c_ulong)
48+
}
49+
}

0 commit comments

Comments
 (0)