abi: fix bug in checked_sub_duration(), add tests

This commit is contained in:
Mark Poliakov 2025-01-05 14:23:29 +02:00
parent dc76c5b7a8
commit 97e11c3bee
8 changed files with 134 additions and 44 deletions

View File

@ -127,7 +127,7 @@ impl Ext2Fs {
// Free inode blocks
inode.resize(self, 0).await?;
inode.dtime = real_time().seconds as u32;
inode.dtime = real_time().seconds() as u32;
self.write_inode(ino, inode).await?;

View File

@ -199,7 +199,7 @@ impl InodeAccess {
log::info!("ext2: allocated inode #{ino}");
let cache = fs.inode_cache.get().clone();
let now = real_time().seconds as u32;
let now = real_time().seconds() as u32;
let mut imode = InodeMode::default_for_type(ty);
imode.update_permissions(mode);

View File

@ -78,7 +78,7 @@ pub fn range(a: u64, b: u64) -> u64 {
/// Initializes the random generator state
pub fn init() {
let now = monotonic_time();
let random_seed = now.nanoseconds.wrapping_add(now.seconds);
let random_seed = now.subsec_nanos().wrapping_add(now.seconds());
let mut state = RandomState::new(random_seed as u32);
state.fill_buf();

View File

@ -14,9 +14,8 @@ static REAL_TIME: AtomicU64 = AtomicU64::new(0);
#[inline]
fn make_time(ticks: u64) -> SystemTime {
SystemTime {
seconds: ticks / NANOSECONDS_IN_SECOND,
nanoseconds: ticks % NANOSECONDS_IN_SECOND,
unsafe {
SystemTime::new_unchecked(ticks / NANOSECONDS_IN_SECOND, ticks % NANOSECONDS_IN_SECOND)
}
}
@ -33,10 +32,7 @@ pub fn real_time() -> SystemTime {
debug_assert!(nanoseconds < NANOSECONDS_IN_SECOND);
}
SystemTime {
seconds,
nanoseconds,
}
unsafe { SystemTime::new_unchecked(seconds, nanoseconds) }
}
#[inline]

View File

@ -148,7 +148,7 @@ pub struct Node {
impl Metadata {
pub fn now(uid: UserId, gid: GroupId, mode: FileMode) -> Metadata {
let now = real_time().seconds;
let now = real_time().seconds();
Metadata {
mode,
uid,

View File

@ -11,8 +11,9 @@
// TODO temporary
#![allow(missing_docs)]
#[cfg(all(feature = "alloc", not(feature = "rustc-dep-of-std")))]
#[cfg(all(any(feature = "alloc", test), not(feature = "rustc-dep-of-std")))]
extern crate alloc;
#[cfg(feature = "rustc-dep-of-std")]
extern crate rustc_std_alloc as alloc;

View File

@ -1,4 +1,7 @@
use core::{ops::Add, time::Duration};
use core::{
ops::{Add, Sub},
time::Duration,
};
use abi_lib::SyscallRegister;
@ -8,8 +11,8 @@ pub const MILLISECONDS_IN_SECOND: u64 = 1_000;
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct SystemTime {
pub seconds: u64,
pub nanoseconds: u64,
seconds: u64,
nanoseconds: u64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
@ -18,13 +21,6 @@ pub enum ClockType {
RealTime,
}
impl SystemTime {
pub const ZERO: Self = Self {
seconds: 0,
nanoseconds: 0,
};
}
impl SyscallRegister for ClockType {
fn into_syscall_register(self) -> usize {
match self {
@ -43,11 +39,52 @@ impl SyscallRegister for ClockType {
}
impl SystemTime {
pub const ZERO: Self = Self {
seconds: 0,
nanoseconds: 0,
};
pub unsafe fn new_unchecked(seconds: u64, nanoseconds: u64) -> Self {
Self {
seconds,
nanoseconds,
}
}
pub fn new(seconds: u64, nanoseconds: u64) -> Self {
Self::new_opt(seconds, nanoseconds).unwrap()
}
pub fn new_opt(mut seconds: u64, nanoseconds: u64) -> Option<Self> {
seconds = seconds.checked_add(nanoseconds / NANOSECONDS_IN_SECOND)?;
Some(Self {
seconds,
nanoseconds: nanoseconds % NANOSECONDS_IN_SECOND,
})
}
pub fn from_seconds(seconds: u64) -> Self {
Self {
seconds,
nanoseconds: 0,
}
}
pub fn as_millis(&self) -> u128 {
(self.seconds as u128 * MILLISECONDS_IN_SECOND as u128)
+ (self.nanoseconds as u128 / 1000000)
}
#[inline(always)]
pub fn subsec_nanos(&self) -> u64 {
self.nanoseconds
}
#[inline(always)]
pub fn seconds(&self) -> u64 {
self.seconds
}
pub fn checked_add_duration(&self, other: &Duration) -> Option<Self> {
let nanoseconds = self.nanoseconds.checked_add(other.subsec_nanos() as u64)?;
let seconds = nanoseconds / NANOSECONDS_IN_SECOND;
@ -67,7 +104,7 @@ impl SystemTime {
let mut seconds = self.seconds.checked_sub(other.as_secs())?;
let nanoseconds = if self.nanoseconds < other.subsec_nanos() as u64 {
seconds = seconds.checked_sub(1)?;
NANOSECONDS_IN_SECOND + self.seconds - other.subsec_nanos() as u64
NANOSECONDS_IN_SECOND + self.nanoseconds - other.subsec_nanos() as u64
} else {
self.nanoseconds - other.subsec_nanos() as u64
};
@ -105,15 +142,18 @@ impl SystemTime {
impl Add<Duration> for SystemTime {
type Output = SystemTime;
#[inline]
fn add(self, rhs: Duration) -> Self::Output {
let mut seconds = self.seconds + rhs.as_secs();
let mut nanoseconds = self.nanoseconds + rhs.subsec_nanos() as u64;
seconds += nanoseconds / NANOSECONDS_IN_SECOND;
nanoseconds %= NANOSECONDS_IN_SECOND;
Self {
seconds,
nanoseconds,
}
self.checked_add_duration(&rhs).unwrap()
}
}
impl Sub<Duration> for SystemTime {
type Output = SystemTime;
#[inline]
fn sub(self, rhs: Duration) -> Self::Output {
self.checked_sub_duration(&rhs).unwrap()
}
}
@ -121,19 +161,72 @@ impl Add<Duration> for SystemTime {
mod tests {
use core::time::Duration;
use super::SystemTime;
use super::{SystemTime, NANOSECONDS_IN_SECOND};
#[test]
fn test_system_time_math() {
let t0 = SystemTime {
seconds: 1,
nanoseconds: 123000000,
};
let t1 = SystemTime {
seconds: 1,
nanoseconds: 143000000,
};
assert_eq!(t0 + Duration::from_millis(20), t1);
assert_eq!(t1.as_millis(), 1143);
fn time_sub_time() {
let t0 = SystemTime::new(1, NANOSECONDS_IN_SECOND - 1);
let t1 = SystemTime::new(2, 0);
assert_eq!(t0.sub_time(&t1).unwrap_err(), Duration::new(0, 1));
assert_eq!(t1.sub_time(&t0).unwrap(), Duration::new(0, 1));
}
#[test]
fn time_checked_sub_time() {
let t0 = SystemTime::new(1, NANOSECONDS_IN_SECOND - 1);
let t1 = SystemTime::new(2, 0);
assert!(t0.checked_sub_time(&t1).is_none());
assert_eq!(t1.checked_sub_time(&t0).unwrap(), Duration::new(0, 1));
}
#[test]
fn time_sub_duration() {
let t0 = SystemTime::new(2, 1);
assert_eq!(
t0.checked_sub_duration(&Duration::new(1, 1)).unwrap(),
SystemTime::new(1, 0)
);
assert_eq!(
t0.checked_sub_duration(&Duration::new(1, 2)).unwrap(),
SystemTime::new(0, NANOSECONDS_IN_SECOND - 1)
);
assert_eq!(
t0.checked_sub_duration(&Duration::new(1, NANOSECONDS_IN_SECOND as u32 - 1))
.unwrap(),
SystemTime::new(0, 2)
);
assert_eq!(
t0.checked_sub_duration(&Duration::new(2, 1)).unwrap(),
SystemTime::ZERO
);
assert!(t0.checked_sub_duration(&Duration::new(2, 2)).is_none());
}
#[test]
fn time_add_duration() {
let t0 = SystemTime::new(2, 1);
let t1 = SystemTime::new(u64::MAX, 1);
assert_eq!(
t0.checked_add_duration(&Duration::new(1, 0)).unwrap(),
SystemTime::new(3, 1)
);
assert_eq!(
t0.checked_add_duration(&Duration::new(1, NANOSECONDS_IN_SECOND as u32 - 1))
.unwrap(),
SystemTime::new(4, 0)
);
assert_eq!(
t1.checked_add_duration(&Duration::new(0, NANOSECONDS_IN_SECOND as u32 - 2))
.unwrap(),
SystemTime::new(u64::MAX, NANOSECONDS_IN_SECOND - 1)
);
assert!(t1
.checked_add_duration(&Duration::new(0, NANOSECONDS_IN_SECOND as u32 - 1))
.is_none());
assert!(t1.checked_add_duration(&Duration::new(1, 0)).is_none());
}
}

View File

@ -13,7 +13,7 @@ enum Error {
fn run() -> Result<(), Error> {
let now = get_real_time().map_err(Error::GetTime)?;
let now = DateTime::from_timestamp(now.seconds as _, now.nanoseconds as _).ok_or(Error::UtcTime)?;
let now = DateTime::from_timestamp(now.seconds() as _, now.subsec_nanos() as _).ok_or(Error::UtcTime)?;
println!("{now}");
Ok(())
}