Add normalize for timeval_t and const value for time

This commit is contained in:
Marsman1996 2024-09-19 11:09:36 +08:00 committed by Tate, Hongliang Tian
parent 4fa4e5ef2a
commit b4003b8aeb
2 changed files with 27 additions and 7 deletions

View File

@ -19,9 +19,10 @@ pub fn sys_select(
let timeout = if timeval_addr == 0 { let timeout = if timeval_addr == 0 {
None None
} else { } else {
let mut timeval = ctx.get_user_space().read_val::<timeval_t>(timeval_addr)?; let timeval = ctx
timeval.sec += timeval.usec / 1_000_000; .get_user_space()
timeval.usec %= 1_000_000; .read_val::<timeval_t>(timeval_addr)?
.normalize();
Some(Duration::try_from(timeval)?) Some(Duration::try_from(timeval)?)
}; };

View File

@ -21,6 +21,10 @@ pub type time_t = i64;
pub type suseconds_t = i64; pub type suseconds_t = i64;
pub type clock_t = i64; pub type clock_t = i64;
const NSEC_PER_USEC: i64 = 1_000;
const USEC_PER_SEC: i64 = 1_000_000;
const NSEC_PER_SEC: i64 = 1_000_000_000;
pub(super) fn init() { pub(super) fn init() {
system_time::init(); system_time::init();
clocks::init(); clocks::init();
@ -46,7 +50,7 @@ impl From<Duration> for timespec_t {
impl From<timeval_t> for timespec_t { impl From<timeval_t> for timespec_t {
fn from(timeval: timeval_t) -> timespec_t { fn from(timeval: timeval_t) -> timespec_t {
let sec = timeval.sec; let sec = timeval.sec;
let nsec = timeval.usec * 1000; let nsec = timeval.usec * NSEC_PER_USEC;
debug_assert!(sec >= 0); // nsec >= 0 always holds debug_assert!(sec >= 0); // nsec >= 0 always holds
timespec_t { sec, nsec } timespec_t { sec, nsec }
} }
@ -60,7 +64,7 @@ impl TryFrom<timespec_t> for Duration {
return_errno_with_message!(Errno::EINVAL, "timesepc_t cannot be negative"); return_errno_with_message!(Errno::EINVAL, "timesepc_t cannot be negative");
} }
if value.nsec > 1_000_000_000 { if value.nsec > NSEC_PER_SEC {
// The value of nanoseconds cannot exceed 10^9, // The value of nanoseconds cannot exceed 10^9,
// otherwise the value for seconds should be set. // otherwise the value for seconds should be set.
return_errno_with_message!(Errno::EINVAL, "nsec is not normalized"); return_errno_with_message!(Errno::EINVAL, "nsec is not normalized");
@ -77,6 +81,21 @@ pub struct timeval_t {
pub usec: suseconds_t, pub usec: suseconds_t,
} }
impl timeval_t {
/// Normalizes time by adding carries from microseconds to seconds.
///
/// Some Linux system calls do this before checking the validity (e.g., the [select]
/// implementation).
///
/// [select]: https://elixir.bootlin.com/linux/v6.10.5/source/fs/select.c#L716
pub fn normalize(&self) -> Self {
Self {
sec: self.sec.wrapping_add(self.usec / USEC_PER_SEC),
usec: self.usec % USEC_PER_SEC,
}
}
}
impl From<Duration> for timeval_t { impl From<Duration> for timeval_t {
fn from(duration: Duration) -> timeval_t { fn from(duration: Duration) -> timeval_t {
let sec = duration.as_secs() as time_t; let sec = duration.as_secs() as time_t;
@ -93,7 +112,7 @@ impl TryFrom<timeval_t> for Duration {
if timeval.sec < 0 || timeval.usec < 0 { if timeval.sec < 0 || timeval.usec < 0 {
return_errno_with_message!(Errno::EINVAL, "timeval_t cannot be negative"); return_errno_with_message!(Errno::EINVAL, "timeval_t cannot be negative");
} }
if timeval.usec > 1_000_000 { if timeval.usec > USEC_PER_SEC {
// The value of microsecond cannot exceed 10^6, // The value of microsecond cannot exceed 10^6,
// otherwise the value for seconds should be set. // otherwise the value for seconds should be set.
return_errno_with_message!(Errno::EINVAL, "nsec is not normalized"); return_errno_with_message!(Errno::EINVAL, "nsec is not normalized");
@ -101,7 +120,7 @@ impl TryFrom<timeval_t> for Duration {
Ok(Duration::new( Ok(Duration::new(
timeval.sec as u64, timeval.sec as u64,
(timeval.usec * 1000) as u32, (timeval.usec * NSEC_PER_USEC) as u32,
)) ))
} }
} }