From ffaccedf953b7d64b6b837a5534849338726473c Mon Sep 17 00:00:00 2001 From: "Hui, Chunyang" Date: Tue, 22 Feb 2022 05:58:11 +0000 Subject: [PATCH] Add support for clock_nanosleep Also replace nanosleep implementation with clock_nanosleep --- src/Enclave.edl | 3 +- src/libos/src/syscall/mod.rs | 23 +++++++++++++- src/libos/src/time/mod.rs | 58 ++++++++++++++++++++++++++++-------- src/pal/src/ocalls/time.c | 5 ++-- 4 files changed, 73 insertions(+), 16 deletions(-) diff --git a/src/Enclave.edl b/src/Enclave.edl index 17de3633..dceee1a8 100644 --- a/src/Enclave.edl +++ b/src/Enclave.edl @@ -141,7 +141,8 @@ enclave { void occlum_ocall_rdtsc([out] uint32_t* low, [out] uint32_t* high); void occlum_ocall_get_timerslack([out] int *timer_slack); - int occlum_ocall_nanosleep( + int occlum_ocall_clock_nanosleep( + clockid_t clockid, int flags, [in] const struct timespec* req, [out] struct timespec* rem ) propagate_errno; diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index 1f52c004..6b8bbe95 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -318,7 +318,7 @@ macro_rules! process_syscall_table_with_callback { (ClockSettime = 227) => handle_unsupported(), (ClockGettime = 228) => do_clock_gettime(clockid: clockid_t, ts_u: *mut timespec_t), (ClockGetres = 229) => do_clock_getres(clockid: clockid_t, res_u: *mut timespec_t), - (ClockNanosleep = 230) => handle_unsupported(), + (ClockNanosleep = 230) => do_clock_nanosleep(clockid: clockid_t, flags: i32, request: *const timespec_t, remain: *mut timespec_t), (ExitGroup = 231) => do_exit_group(exit_status: i32, user_context: *mut CpuContext), (EpollWait = 232) => do_epoll_wait(epfd: c_int, events: *mut libc::epoll_event, maxevents: c_int, timeout: c_int), (EpollCtl = 233) => do_epoll_ctl(epfd: c_int, op: c_int, fd: c_int, event: *const libc::epoll_event), @@ -885,6 +885,27 @@ fn do_clock_getres(clockid: clockid_t, res_u: *mut timespec_t) -> Result Ok(0) } +fn do_clock_nanosleep( + clockid: clockid_t, + flags: i32, + req_u: *const timespec_t, + rem_u: *mut timespec_t, +) -> Result { + let req = { + check_ptr(req_u)?; + timespec_t::from_raw_ptr(req_u)? + }; + let rem = if !rem_u.is_null() { + check_mut_ptr(rem_u)?; + Some(unsafe { &mut *rem_u }) + } else { + None + }; + let clockid = time::ClockID::from_raw(clockid)?; + time::do_clock_nanosleep(clockid, flags, &req, rem)?; + Ok(0) +} + // TODO: handle remainder fn do_nanosleep(req_u: *const timespec_t, rem_u: *mut timespec_t) -> Result { let req = { diff --git a/src/libos/src/time/mod.rs b/src/libos/src/time/mod.rs index f5172fe6..45b2e021 100644 --- a/src/libos/src/time/mod.rs +++ b/src/libos/src/time/mod.rs @@ -188,29 +188,63 @@ pub fn do_clock_getres(clockid: ClockID) -> Result { Ok(res) } -pub fn do_nanosleep(req: ×pec_t, rem: Option<&mut timespec_t>) -> Result<()> { +const TIMER_ABSTIME: i32 = 0x01; + +pub fn do_clock_nanosleep( + clockid: ClockID, + flags: i32, + req: ×pec_t, + rem: Option<&mut timespec_t>, +) -> Result<()> { extern "C" { - fn occlum_ocall_nanosleep( + fn occlum_ocall_clock_nanosleep( ret: *mut i32, + clockid: clockid_t, + flags: i32, req: *const timespec_t, rem: *mut timespec_t, ) -> sgx_status_t; } - unsafe { - let mut ret = 0; - let mut u_rem: timespec_t = timespec_t { sec: 0, nsec: 0 }; - let sgx_status = occlum_ocall_nanosleep(&mut ret, req, &mut u_rem); - assert!(sgx_status == sgx_status_t::SGX_SUCCESS); - assert!(ret == 0 || libc::errno() == Errno::EINTR as i32); - if ret != 0 { - assert!(u_rem.as_duration() <= req.as_duration() + (*TIMERSLACK).to_duration()); + + let mut ret = 0; + let mut u_rem: timespec_t = timespec_t { sec: 0, nsec: 0 }; + match clockid { + ClockID::CLOCK_REALTIME + | ClockID::CLOCK_MONOTONIC + | ClockID::CLOCK_BOOTTIME + | ClockID::CLOCK_PROCESS_CPUTIME_ID => {} + ClockID::CLOCK_THREAD_CPUTIME_ID => { + return_errno!(EINVAL, "CLOCK_THREAD_CPUTIME_ID is not a permitted value"); + } + _ => { + return_errno!(EOPNOTSUPP, "does not support sleeping against this clockid"); + } + } + let sgx_status = unsafe { + occlum_ocall_clock_nanosleep(&mut ret, clockid as clockid_t, flags, req, &mut u_rem) + }; + assert!(sgx_status == sgx_status_t::SGX_SUCCESS); + assert!(ret == 0 || ret == Errno::EINTR as i32); + if ret != 0 { + assert!(u_rem.as_duration() <= req.as_duration() + (*TIMERSLACK).to_duration()); + // rem is only valid if TIMER_ABSTIME flag is not set + if flags != TIMER_ABSTIME { if let Some(rem) = rem { *rem = u_rem; } - return_errno!(EINTR, "sleep interrupted"); } + return_errno!(EINTR, "sleep interrupted"); } - Ok(()) + return Ok(()); +} + +pub fn do_nanosleep(req: ×pec_t, rem: Option<&mut timespec_t>) -> Result<()> { + // POSIX.1 specifies that nanosleep() should measure time against + // the CLOCK_REALTIME clock. However, Linux measures the time using + // the CLOCK_MONOTONIC clock. + // Here we follow the POSIX.1 + let clock_id = ClockID::CLOCK_REALTIME; + return do_clock_nanosleep(clock_id, 0, req, rem); } pub fn do_thread_getcpuclock() -> Result { diff --git a/src/pal/src/ocalls/time.c b/src/pal/src/ocalls/time.c index 14be93e8..7bfcf737 100644 --- a/src/pal/src/ocalls/time.c +++ b/src/pal/src/ocalls/time.c @@ -16,8 +16,9 @@ void occlum_ocall_clock_getres(int clockid, struct timespec *res) { clock_getres(clockid, res); } -int occlum_ocall_nanosleep(const struct timespec *req, struct timespec *rem) { - return nanosleep(req, rem); +int occlum_ocall_clock_nanosleep(clockid_t clockid, int flags, const struct timespec *req, + struct timespec *rem) { + return clock_nanosleep(clockid, flags, req, rem); } int occlum_ocall_thread_getcpuclock(struct timespec *tp) {