Skip to content

Commit 4521438

Browse files
LyudeAndreas Hindborg
authored andcommitted
rust: time: Implement basic arithmetic operations for Delta
While rvkms is only going to be using a few of these, since Deltas are basically the same as i64 it's easy enough to just implement all of the basic arithmetic operations for Delta types. Keep in mind there's one quirk here - the kernel has no support for i64 % i64 on 32 bit platforms, the closest we have is i64 % i32 through div_s64_rem(). So, instead of implementing ops::Rem or ops::RemAssign we simply provide Delta::rem_nanos(). Signed-off-by: Lyude Paul <[email protected]> Reviewed-by: Daniel Almeida <[email protected]> Reviewed-by: FUJITA Tomonori <[email protected]> Reviewed-by: Andreas Hindborg <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Andreas Hindborg <[email protected]>
1 parent 22b65a4 commit 4521438

File tree

1 file changed

+98
-0
lines changed

1 file changed

+98
-0
lines changed

rust/kernel/time.rs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,78 @@ pub struct Delta {
287287
nanos: i64,
288288
}
289289

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+
290362
impl Delta {
291363
/// A span of time equal to zero.
292364
pub const ZERO: Self = Self { nanos: 0 };
@@ -375,4 +447,30 @@ impl Delta {
375447
bindings::ktime_to_ms(self.as_nanos())
376448
}
377449
}
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+
}
378476
}

0 commit comments

Comments
 (0)