Skip to main content

kernel_api/
time.rs

1//! Temporal quantification.
2//!
3//! # Examples
4//!
5//! Using [`Instant`] to calculate how long a function took to run:
6//!
7//! ```ignore (incomplete)
8//! # use kernel_api::time::Instant;
9//! let now = Instant::now();
10//!
11//! // Calling a slow function, it may take a while
12//! slow_function();
13//!
14//! let elapsed_time = now.elapsed();
15//! println!("Running slow_function() took {} seconds.", elapsed_time.as_secs());
16//! ```
17
18use core::ops::{Add, AddAssign, Sub, SubAssign};
19use core::time::Duration;
20
21/// A measurement of the current system time.
22/// Opaque and useful only with [`Duration`].
23///
24/// Instants are opaque types that should usually only be compared to one another.
25/// [`get()`] can be used to get the internal value, but no guarantees are made about
26/// the meaning of the value. The meaning of the result of `get()` varies by system
27/// and may even change at runtime during a single boot. A best-attempt value of the
28/// time since system boot can be retrieved with [`nanos_since_boot()`].
29///
30/// The size of an `Instant` struct may vary depending on the target platform.
31///
32/// Example:
33///
34/// ```compile_fail (incomplete)
35/// use core::time::Duration;
36/// use kernel_api::time::Instant;
37/// use kernel_api::threading::sleep;
38/// use kernel_api::executor::block_on;
39///
40/// fn main() {
41///    let now = Instant::now();
42///
43///    // we sleep for 2 seconds
44///    block_on(sleep(Duration::new(2, 0)));
45///    // it prints '2'
46///    sprintln!("{}", now.elapsed().as_secs());
47/// }
48/// ```
49///
50/// # Underlying system
51///
52/// The following mechanisms are currently being used by `now()` to find out
53/// the current time:
54///
55/// | Platform | Mechanism           |
56/// |----------|---------------------|
57/// | `x86_64` | `rdtsc` instruction |
58///
59/// <div class="warning">
60/// These mechanisms might change over time.
61/// </div>
62///
63/// > Note: mathematical operations like [`add()`](`Instant::add`) may panic if the underlying
64/// > structure cannot represent the new point in time.
65#[derive(Copy, Clone, Hash, Debug, Ord, PartialOrd, Eq, PartialEq)]
66pub struct Instant {
67	arch_val: u128
68}
69
70impl Instant {
71	fn nanos(&self) -> u128 {
72		Self::arch_to_nanos(self.arch_val)
73	}
74	
75	fn arch_to_nanos(arch_val: u128) -> u128 {
76		let (num, denom) = crate::bridge::time::system_time_to_nanos();
77
78		arch_val * num / denom.get()
79	}
80
81	fn nanos_to_arch(nanos: u128) -> u128 {
82		let (num, denom) = crate::bridge::time::system_time_to_nanos();
83
84		nanos * denom.get() / num
85	}
86	
87	/// The current system time.
88	///
89	/// # Examples
90	///
91    /// ```
92    /// use kernel_api::time::Instant;
93    ///
94    /// let now = Instant::now();
95    /// ```
96	#[must_use]
97	pub fn now() -> Self {
98		let arch_val = crate::bridge::time::system_time();
99		Self {
100			arch_val
101		}
102	}
103
104	/// Returns the amount of time elapsed from another instant to this one.
105	///
106	/// # Panics
107	///
108	/// This method may panic if `self` is earlier than `earlier`.
109	///
110    /// # Examples
111    ///
112    /// ```compile_fail (incomplete)
113	/// use core::time::Duration;
114	/// use kernel_api::time::Instant;
115	/// use kernel_api::threading::sleep;
116	/// use kernel_api::executor::block_on;
117    ///
118    /// let now = Instant::now();
119    /// block_on(sleep(Duration::new(1, 0)));
120    /// let new_now = Instant::now();
121    /// sprintln!("{:?}", new_now.duration_since(now));
122    /// ```
123	#[must_use = "this returns the result of the operation, without modifying the original"]
124	pub fn duration_since(&self, earlier: Self) -> Duration {
125		self.saturating_duration_since(earlier)
126	}
127
128	/// Returns the amount of time elapsed from another instant to this one,
129    /// or None if that instant is later than this one.
130    ///
131    /// # Examples
132    ///
133    /// ```compile_fail (incomplete)
134	/// use core::time::Duration;
135	/// use kernel_api::time::Instant;
136	/// use kernel_api::threading::sleep;
137	/// use kernel_api::executor::block_on;
138    ///
139    /// let now = Instant::now();
140    /// block_on(sleep(Duration::new(1, 0)));
141    /// let new_now = Instant::now();
142    /// sprintln!("{:?}", new_now.checked_duration_since(now));
143    /// sprintln!("{:?}", now.checked_duration_since(new_now)); // None
144    /// ```
145	#[must_use = "this returns the result of the operation, without modifying the original"]
146	pub fn checked_duration_since(&self, earlier: Self) -> Option<Duration> {
147		let nanos = self.nanos().checked_sub(earlier.nanos())?;
148		Some(Duration::new(
149			(nanos / 1_000_000_000) as u64,
150			(nanos % 1_000_000_000) as u32
151		))
152	}
153
154	/// Returns the amount of time elapsed from another instant to this one,
155    /// or zero duration if that instant is later than this one.
156    ///
157    /// # Examples
158    ///
159    /// ```compile_fail (incomplete)
160	/// use core::time::Duration;
161	/// use kernel_api::time::Instant;
162	/// use kernel_api::threading::sleep;
163	/// use kernel_api::executor::block_on;
164    ///
165    /// let now = Instant::now();
166    /// block_on(sleep(Duration::new(1, 0)));
167    /// let new_now = Instant::now();
168    /// sprintln!("{:?}", new_now.saturating_duration_since(now));
169    /// sprintln!("{:?}", now.saturating_duration_since(new_now)); // 0ns
170    /// ```
171	#[must_use = "this returns the result of the operation, without modifying the original"]
172	pub fn saturating_duration_since(&self, earlier: Self) -> Duration {
173		let nanos = self.nanos().saturating_sub(earlier.nanos());
174		Duration::new(
175			(nanos / 1_000_000_000) as u64,
176			(nanos % 1_000_000_000) as u32
177		)
178	}
179
180	/// Returns the amount of time elapsed since this instant.
181    ///
182    /// # Panics
183    ///
184    /// This method may panic if the current time is earlier than `self`.
185    ///
186    /// # Examples
187    ///
188    /// ```compile_fail (incomplete)
189	/// use core::time::Duration;
190	/// use kernel_api::time::Instant;
191	/// use kernel_api::threading::sleep;
192	/// use kernel_api::executor::block_on;
193    ///
194    /// let instant = Instant::now();
195    /// let three_secs = Duration::from_secs(3);
196    /// block_on(sleep(three_secs));
197    /// assert!(instant.elapsed() >= three_secs);
198    /// ```
199	#[must_use = "this returns the result of the operation, without modifying the original"]
200	pub fn elapsed(&self) -> Duration {
201		Self::now() - *self
202	}
203
204	/// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be represented as
205    /// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
206    /// otherwise.
207	#[must_use = "this returns the result of the operation, without modifying the original"]
208	pub fn checked_add(&self, duration: Duration) -> Option<Self> {
209		let arch_val = self.arch_val.checked_add(Self::nanos_to_arch(duration.as_nanos()))?;
210		Some(Self { arch_val })
211	}
212
213	/// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be represented as
214    /// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
215    /// otherwise.
216	#[must_use = "this returns the result of the operation, without modifying the original"]
217	pub fn checked_sub(&self, duration: Duration) -> Option<Self> {
218		let arch_val = self.arch_val.checked_sub(Self::nanos_to_arch(duration.as_nanos()))?;
219		Some(Self { arch_val })
220	}
221	
222	/// The number of nanoseconds since the system booted.
223	/// 
224	/// No guarantees are provided on time before overflow.
225	#[must_use]
226	pub fn nanos_since_boot(&self) -> u128 {
227		self.nanos()
228	}
229	
230	/// Returns the opaque numeric value of the instant.
231	/// 
232	/// The meaning of the returned value is architecture dependant, see the
233	/// [struct level documentation](`Instant#underlying-system`) for more information.
234	#[must_use]
235	pub const fn get(&self) -> u128 { self.arch_val }
236}
237
238impl Add<Duration> for Instant {
239	type Output = Self;
240
241	/// # Panics
242    ///
243    /// This function may panic if the resulting point in time cannot be represented by the
244    /// underlying data structure. See [`Instant::checked_add`] for a version without panic.
245	#[track_caller]
246	fn add(self, rhs: Duration) -> Self::Output {
247		Self { arch_val: self.arch_val + Self::nanos_to_arch(rhs.as_nanos()) }
248	}
249}
250
251impl AddAssign<Duration> for Instant {
252	fn add_assign(&mut self, rhs: Duration) {
253		self.arch_val += Self::nanos_to_arch(rhs.as_nanos());
254	}
255}
256
257impl Sub for Instant {
258	type Output = Duration;
259
260	fn sub(self, rhs: Self) -> Self::Output {
261		self.duration_since(rhs)
262	}
263}
264
265impl Sub<Duration> for Instant {
266	type Output = Self;
267
268	/// # Panics
269    ///
270    /// This function may panic if the resulting point in time cannot be represented by the
271    /// underlying data structure. See [`Instant::checked_sub`] for a version without panic.
272	#[track_caller]
273	fn sub(self, rhs: Duration) -> Self::Output {
274		Self { arch_val: self.arch_val - Self::nanos_to_arch(rhs.as_nanos()) }
275	}
276}
277
278impl SubAssign<Duration> for Instant {
279	fn sub_assign(&mut self, rhs: Duration) {
280		self.arch_val -= Self::nanos_to_arch(rhs.as_nanos());
281	}
282}