arceos_posix_api/imp/
time.rs

1use axerrno::LinuxError;
2use core::ffi::{c_int, c_long};
3use core::time::Duration;
4
5use crate::ctypes;
6use crate::ctypes::{CLOCK_MONOTONIC, CLOCK_REALTIME};
7
8impl From<ctypes::timespec> for Duration {
9    fn from(ts: ctypes::timespec) -> Self {
10        Duration::new(ts.tv_sec as u64, ts.tv_nsec as u32)
11    }
12}
13
14impl From<ctypes::timeval> for Duration {
15    fn from(tv: ctypes::timeval) -> Self {
16        Duration::new(tv.tv_sec as u64, tv.tv_usec as u32 * 1000)
17    }
18}
19
20impl From<Duration> for ctypes::timespec {
21    fn from(d: Duration) -> Self {
22        ctypes::timespec {
23            tv_sec: d.as_secs() as c_long,
24            tv_nsec: d.subsec_nanos() as c_long,
25        }
26    }
27}
28
29impl From<Duration> for ctypes::timeval {
30    fn from(d: Duration) -> Self {
31        ctypes::timeval {
32            tv_sec: d.as_secs() as c_long,
33            tv_usec: d.subsec_micros() as c_long,
34        }
35    }
36}
37
38/// Get clock time since booting
39pub unsafe fn sys_clock_gettime(clk: ctypes::clockid_t, ts: *mut ctypes::timespec) -> c_int {
40    syscall_body!(sys_clock_gettime, {
41        if ts.is_null() {
42            return Err(LinuxError::EFAULT);
43        }
44        let now = match clk as u32 {
45            CLOCK_REALTIME => axhal::time::wall_time().into(),
46            CLOCK_MONOTONIC => axhal::time::monotonic_time().into(),
47            _ => {
48                warn!("Called sys_clock_gettime for unsupported clock {}", clk);
49                return Err(LinuxError::EINVAL);
50            }
51        };
52        unsafe { *ts = now };
53        debug!("sys_clock_gettime: {}.{:09}s", now.tv_sec, now.tv_nsec);
54        Ok(0)
55    })
56}
57
58/// Sleep some nanoseconds
59///
60/// TODO: should be woken by signals, and set errno
61pub unsafe fn sys_nanosleep(req: *const ctypes::timespec, rem: *mut ctypes::timespec) -> c_int {
62    syscall_body!(sys_nanosleep, {
63        unsafe {
64            if req.is_null() || (*req).tv_nsec < 0 || (*req).tv_nsec > 999999999 {
65                return Err(LinuxError::EINVAL);
66            }
67        }
68
69        let dur = unsafe {
70            debug!("sys_nanosleep <= {}.{:09}s", (*req).tv_sec, (*req).tv_nsec);
71            Duration::from(*req)
72        };
73
74        let now = axhal::time::monotonic_time();
75
76        #[cfg(feature = "multitask")]
77        axtask::sleep(dur);
78        #[cfg(not(feature = "multitask"))]
79        axhal::time::busy_wait(dur);
80
81        let after = axhal::time::monotonic_time();
82        let actual = after - now;
83
84        if let Some(diff) = dur.checked_sub(actual) {
85            if !rem.is_null() {
86                unsafe { (*rem) = diff.into() };
87            }
88            return Err(LinuxError::EINTR);
89        }
90        Ok(0)
91    })
92}