Skip to content

Commit a93d1dd

Browse files
hoshinolinajannau
authored andcommitted
rust: time: New module for timekeeping functions
This module is intended to contain functions related to kernel timekeeping and time. Initially, this just wraps ktime_get() and ktime_get_boottime() and returns them as core::time::Duration instances. Signed-off-by: Asahi Lina <lina@asahilina.net>
1 parent ac1cc63 commit a93d1dd

4 files changed

Lines changed: 168 additions & 1 deletion

File tree

rust/bindings/bindings_helper.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <linux/ioport.h>
2222
#include <linux/jiffies.h>
2323
#include <linux/jump_label.h>
24+
#include <linux/ktime.h>
2425
#include <linux/lockdep.h>
2526
#include <linux/mdio.h>
2627
#include <linux/miscdevice.h>
@@ -36,6 +37,7 @@
3637
#include <linux/sched.h>
3738
#include <linux/security.h>
3839
#include <linux/slab.h>
40+
#include <linux/timekeeping.h>
3941
#include <linux/tracepoint.h>
4042
#include <linux/wait.h>
4143
#include <linux/workqueue.h>

rust/helpers/helpers.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "slab.c"
3535
#include "spinlock.c"
3636
#include "task.c"
37+
#include "timekeeping.c"
3738
#include "uaccess.c"
3839
#include "vmalloc.c"
3940
#include "wait.c"

rust/helpers/timekeeping.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <linux/timekeeping.h>
4+
5+
ktime_t rust_helper_ktime_get_real(void) {
6+
return ktime_get_real();
7+
}
8+
9+
ktime_t rust_helper_ktime_get_boottime(void) {
10+
return ktime_get_boottime();
11+
}
12+
13+
ktime_t rust_helper_ktime_get_clocktai(void) {
14+
return ktime_get_clocktai();
15+
}

rust/kernel/time.rs

Lines changed: 150 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
// SPDX-License-Identifier: GPL-2.0
22

3-
//! Time related primitives.
3+
//! Time related primitives and functions.
44
//!
55
//! This module contains the kernel APIs related to time and timers that
66
//! have been ported or wrapped for usage by Rust code in the kernel.
77
//!
88
//! C header: [`include/linux/jiffies.h`](srctree/include/linux/jiffies.h).
99
//! C header: [`include/linux/ktime.h`](srctree/include/linux/ktime.h).
10+
//! C header: [`include/linux/timekeeping.h`](srctree/include/linux/timekeeping.h)
1011
1112
/// The number of nanoseconds per millisecond.
1213
pub const NSEC_PER_MSEC: i64 = bindings::NSEC_PER_MSEC as i64;
@@ -81,3 +82,151 @@ impl core::ops::Sub for Ktime {
8182
}
8283
}
8384
}
85+
86+
use crate::{bindings, pr_err};
87+
use core::marker::PhantomData;
88+
use core::time::Duration;
89+
90+
/// Represents a clock, that is, a unique time source.
91+
pub trait Clock: Sized {}
92+
93+
/// A time source that can be queried for the current time.
94+
pub trait Now: Clock {
95+
/// Returns the current time for this clock.
96+
fn now() -> Instant<Self>;
97+
}
98+
99+
/// Marker trait for clock sources that are guaranteed to be monotonic.
100+
pub trait Monotonic {}
101+
102+
/// Marker trait for clock sources that represent a calendar (wall clock)
103+
/// relative to the UNIX epoch.
104+
pub trait WallTime {}
105+
106+
/// An instant in time associated with a given clock source.
107+
#[derive(Debug)]
108+
pub struct Instant<T: Clock> {
109+
nanoseconds: i64,
110+
_type: PhantomData<T>,
111+
}
112+
113+
impl<T: Clock> Clone for Instant<T> {
114+
fn clone(&self) -> Self {
115+
*self
116+
}
117+
}
118+
119+
impl<T: Clock> Copy for Instant<T> {}
120+
121+
impl<T: Clock> Instant<T> {
122+
fn new(nanoseconds: i64) -> Self {
123+
Instant {
124+
nanoseconds,
125+
_type: PhantomData,
126+
}
127+
}
128+
129+
/// Returns the time elapsed since an earlier Instant<t>, or
130+
/// None if the argument is a later Instant.
131+
pub fn since(&self, earlier: Instant<T>) -> Option<Duration> {
132+
if earlier.nanoseconds > self.nanoseconds {
133+
None
134+
} else {
135+
// Casting to u64 and subtracting is guaranteed to give the right
136+
// result for all inputs, as long as the condition we checked above
137+
// holds.
138+
Some(Duration::from_nanos(
139+
self.nanoseconds as u64 - earlier.nanoseconds as u64,
140+
))
141+
}
142+
}
143+
}
144+
145+
impl<T: Clock + Now + Monotonic> Instant<T> {
146+
/// Returns the time elapsed since this Instant<T>.
147+
///
148+
/// This is guaranteed to return a positive result, since
149+
/// it is only implemented for monotonic clocks.
150+
pub fn elapsed(&self) -> Duration {
151+
T::now().since(*self).unwrap_or_else(|| {
152+
pr_err!(
153+
"Monotonic clock {} went backwards!",
154+
core::any::type_name::<T>()
155+
);
156+
Duration::ZERO
157+
})
158+
}
159+
}
160+
161+
/// Contains the various clock source types available to the kernel.
162+
pub mod clock {
163+
use super::*;
164+
165+
/// A clock representing the default kernel time source.
166+
///
167+
/// This is `CLOCK_MONOTONIC` (though it is not the only
168+
/// monotonic clock) and also the default clock used by
169+
/// `ktime_get()` in the C API.
170+
///
171+
/// This is like `BootTime`, but does not include time
172+
/// spent sleeping.
173+
174+
pub struct KernelTime;
175+
176+
impl Clock for KernelTime {}
177+
impl Monotonic for KernelTime {}
178+
impl Now for KernelTime {
179+
fn now() -> Instant<Self> {
180+
// SAFETY: Always safe to call
181+
Instant::<Self>::new(unsafe { bindings::ktime_get() })
182+
}
183+
}
184+
185+
/// A clock representing the time elapsed since boot.
186+
///
187+
/// This is `CLOCK_MONOTONIC` (though it is not the only
188+
/// monotonic clock) and also the default clock used by
189+
/// `ktime_get()` in the C API.
190+
///
191+
/// This is like `KernelTime`, but does include time
192+
/// spent sleeping.
193+
pub struct BootTime;
194+
195+
impl Clock for BootTime {}
196+
impl Monotonic for BootTime {}
197+
impl Now for BootTime {
198+
fn now() -> Instant<Self> {
199+
// SAFETY: Always safe to call
200+
Instant::<Self>::new(unsafe { bindings::ktime_get_boottime() })
201+
}
202+
}
203+
204+
/// A clock representing TAI time.
205+
///
206+
/// This clock is not monotonic and can be changed from userspace.
207+
/// However, it is not affected by leap seconds.
208+
pub struct TaiTime;
209+
210+
impl Clock for TaiTime {}
211+
impl WallTime for TaiTime {}
212+
impl Now for TaiTime {
213+
fn now() -> Instant<Self> {
214+
// SAFETY: Always safe to call
215+
Instant::<Self>::new(unsafe { bindings::ktime_get_clocktai() })
216+
}
217+
}
218+
219+
/// A clock representing wall clock time.
220+
///
221+
/// This clock is not monotonic and can be changed from userspace.
222+
pub struct RealTime;
223+
224+
impl Clock for RealTime {}
225+
impl WallTime for RealTime {}
226+
impl Now for RealTime {
227+
fn now() -> Instant<Self> {
228+
// SAFETY: Always safe to call
229+
Instant::<Self>::new(unsafe { bindings::ktime_get_real() })
230+
}
231+
}
232+
}

0 commit comments

Comments
 (0)