diff --git a/src/Cargo.lock b/src/Cargo.lock index ecedeaff..f6dc75f5 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -310,6 +310,7 @@ dependencies = [ "pod", "ringbuffer", "spin 0.9.4", + "time", "typeflags", "typeflags-util", "virtio-input-decoder", @@ -559,6 +560,22 @@ dependencies = [ "syn", ] +[[package]] +name = "time" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" +dependencies = [ + "serde", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" + [[package]] name = "toml" version = "0.7.2" diff --git a/src/services/libs/jinux-std/Cargo.toml b/src/services/libs/jinux-std/Cargo.toml index 74f94bbe..28d2cf6d 100644 --- a/src/services/libs/jinux-std/Cargo.toml +++ b/src/services/libs/jinux-std/Cargo.toml @@ -19,6 +19,7 @@ cpio-decoder = {path="../cpio-decoder"} virtio-input-decoder = "0.1.4" ascii = { version = "1.1", default-features = false, features = ["alloc"] } intrusive-collections = "0.9.5" +time = { version = "0.3", default-features = false, features = ["alloc"] } # parse elf file xmas-elf = "0.8.0" diff --git a/src/services/libs/jinux-std/src/syscall/mod.rs b/src/services/libs/jinux-std/src/syscall/mod.rs index e4e5ca0b..61181833 100644 --- a/src/services/libs/jinux-std/src/syscall/mod.rs +++ b/src/services/libs/jinux-std/src/syscall/mod.rs @@ -207,6 +207,7 @@ define_syscall_nums!( SYS_PRCTL = 157, SYS_ARCH_PRCTL = 158, SYS_GETTID = 186, + SYS_TIME = 201, SYS_FUTEX = 202, SYS_SET_TID_ADDRESS = 218, SYS_CLOCK_NANOSLEEP = 230, @@ -335,6 +336,7 @@ pub fn syscall_dispatch( SYS_PRCTL => syscall_handler!(5, sys_prctl, args), SYS_ARCH_PRCTL => syscall_handler!(2, sys_arch_prctl, args, context), SYS_GETTID => syscall_handler!(0, sys_gettid), + SYS_TIME => syscall_handler!(1, sys_time, args), SYS_FUTEX => syscall_handler!(6, sys_futex, args), SYS_SET_TID_ADDRESS => syscall_handler!(1, sys_set_tid_address, args), SYS_CLOCK_NANOSLEEP => syscall_handler!(4, sys_clock_nanosleep, args), diff --git a/src/services/libs/jinux-std/src/syscall/time.rs b/src/services/libs/jinux-std/src/syscall/time.rs new file mode 100644 index 00000000..28366239 --- /dev/null +++ b/src/services/libs/jinux-std/src/syscall/time.rs @@ -0,0 +1,16 @@ +use crate::log_syscall_entry; +use crate::prelude::*; +use crate::time::SystemTime; +use crate::util::write_val_to_user; + +use super::SyscallReturn; +use super::SYS_TIME; + +pub fn sys_time(tloc: Vaddr) -> Result { + log_syscall_entry!(SYS_TIME); + debug!("tloc = 0x{tloc:x}"); + let now = SystemTime::now(); + let now_as_secs = now.duration_since(&SystemTime::UNIX_EPOCH)?.as_secs(); + write_val_to_user(tloc, &now_as_secs)?; + Ok(SyscallReturn::Return(0)) +} diff --git a/src/services/libs/jinux-std/src/time/mod.rs b/src/services/libs/jinux-std/src/time/mod.rs index caa621a9..d8558e2c 100644 --- a/src/services/libs/jinux-std/src/time/mod.rs +++ b/src/services/libs/jinux-std/src/time/mod.rs @@ -3,6 +3,9 @@ use core::time::Duration; use crate::prelude::*; +mod system_time; +pub use system_time::SystemTime; + pub type clockid_t = i32; pub type time_t = i64; pub type suseconds_t = i64; diff --git a/src/services/libs/jinux-std/src/time/system_time.rs b/src/services/libs/jinux-std/src/time/system_time.rs new file mode 100644 index 00000000..dac30d4f --- /dev/null +++ b/src/services/libs/jinux-std/src/time/system_time.rs @@ -0,0 +1,93 @@ +use core::time::Duration; + +use crate::prelude::*; +use jinux_frame::time::get_real_time; +use time::{Date, Month, PrimitiveDateTime, Time}; + +/// This struct corresponds to `SystemTime` in Rust std. +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct SystemTime(PrimitiveDateTime); + +impl SystemTime { + /// The unix epoch, which represents 1970-01-01 00:00:00 + pub const UNIX_EPOCH: SystemTime = SystemTime::unix_epoch(); + + const fn unix_epoch() -> Self { + // 1970-01-01 00:00:00 + let date = Date::__from_ordinal_date_unchecked(1970, 1); + let time = Time::__from_hms_nanos_unchecked(0, 0, 0, 0); + SystemTime(PrimitiveDateTime::new(date, time)) + } + + /// Returns the current system time + pub fn now() -> Self { + let system_time = get_real_time(); + // The get real time result should always be valid + convert_system_time(system_time).unwrap() + } + + /// Add a duration to self. If the result does not exceed inner bounds return Some(t), else return None. + pub fn checked_add(&self, duration: Duration) -> Option { + let duration = convert_to_time_duration(duration); + self.0.checked_add(duration).map(|inner| SystemTime(inner)) + } + + /// Substract a duration from self. If the result does not exceed inner bounds return Some(t), else return None. + pub fn checked_sub(&self, duration: Duration) -> Option { + let duration = convert_to_time_duration(duration); + self.0.checked_sub(duration).map(|inner| SystemTime(inner)) + } + + /// Returns the duration since an earlier time. Return error if `earlier` is later than self. + pub fn duration_since(&self, earlier: &SystemTime) -> Result { + if self.0 < earlier.0 { + return_errno_with_message!( + Errno::EINVAL, + "duration_since can only accept an earlier time" + ); + } + let duration = self.0 - earlier.0; + Ok(convert_to_core_duration(duration)) + } + + /// Return the difference between current time and the time when self was created. + /// Return Error if current time is earlier than creating time. + /// The error can happen if self was created by checked_add. + pub fn elapsed(&self) -> Result { + let now = SystemTime::now(); + now.duration_since(self) + } +} + +/// convert jinux_frame::time::Time to System time +fn convert_system_time(system_time: jinux_frame::time::Time) -> Result { + let month = match Month::try_from(system_time.month) { + Ok(month) => month, + Err(_) => return_errno_with_message!(Errno::EINVAL, "unknown month in system time"), + }; + let date = match Date::from_calendar_date(system_time.year as _, month, system_time.day) { + Ok(date) => date, + Err(_) => return_errno_with_message!(Errno::EINVAL, "Invalid system date"), + }; + let time_ = match Time::from_hms(system_time.hour, system_time.minute, system_time.second) { + Ok(time_) => time_, + Err(_) => return_errno_with_message!(Errno::EINVAL, "Invalid system time"), + }; + Ok(SystemTime(PrimitiveDateTime::new(date, time_))) +} + +/// FIXME: need to further check precision loss +/// convert core::time::Duration to time::Duration +const fn convert_to_time_duration(duration: Duration) -> time::Duration { + let seconds = duration.as_secs() as i64; + let nanoseconds = duration.subsec_nanos() as i32; + time::Duration::new(seconds, nanoseconds) +} + +/// FIXME: need to further check precision loss +/// convert time::Duration to core::time::Duration +const fn convert_to_core_duration(duration: time::Duration) -> Duration { + let seconds = duration.whole_seconds() as u64; + let nanoseconds = duration.subsec_nanoseconds() as u32; + Duration::new(seconds, nanoseconds) +}