diff --git a/src/Enclave.edl b/src/Enclave.edl index c4ea828a..48f81a85 100644 --- a/src/Enclave.edl +++ b/src/Enclave.edl @@ -97,6 +97,7 @@ enclave { void occlum_ocall_gettimeofday([out] struct timeval* tv); void occlum_ocall_clock_gettime(clockid_t clockid, [out] struct timespec* ts); + void occlum_ocall_clock_getres(clockid_t clockid, [out] struct timespec* res); void occlum_ocall_rdtsc([out] uint32_t* low, [out] uint32_t* high); void occlum_ocall_nanosleep([in] const struct timespec* req); diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index 4841398d..13e0cb36 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -306,7 +306,7 @@ macro_rules! process_syscall_table_with_callback { (TimerDelete = 226) => handle_unsupported(), (ClockSettime = 227) => handle_unsupported(), (ClockGettime = 228) => do_clock_gettime(clockid: clockid_t, ts_u: *mut timespec_t), - (ClockGetres = 229) => handle_unsupported(), + (ClockGetres = 229) => do_clock_getres(clockid: clockid_t, res_u: *mut timespec_t), (ClockNanosleep = 230) => handle_unsupported(), (ExitGroup = 231) => do_exit_group(exit_status: i32), (EpollWait = 232) => do_epoll_wait(epfd: c_int, events: *mut libc::epoll_event, maxevents: c_int, timeout: c_int), @@ -775,6 +775,19 @@ fn do_clock_gettime(clockid: clockid_t, ts_u: *mut timespec_t) -> Result Ok(0) } +fn do_clock_getres(clockid: clockid_t, res_u: *mut timespec_t) -> Result { + if res_u.is_null() { + return Ok(0); + } + check_mut_ptr(res_u)?; + let clockid = time::ClockID::from_raw(clockid)?; + let res = time::do_clock_getres(clockid)?; + unsafe { + *res_u = res; + } + Ok(0) +} + // TODO: handle remainder fn do_nanosleep(req_u: *const timespec_t, rem_u: *mut timespec_t) -> Result { check_ptr(req_u)?; diff --git a/src/libos/src/time/mod.rs b/src/libos/src/time/mod.rs index 213b50fe..c871b8c2 100644 --- a/src/libos/src/time/mod.rs +++ b/src/libos/src/time/mod.rs @@ -137,6 +137,28 @@ pub fn do_clock_gettime(clockid: ClockID) -> Result { Ok(tv) } +pub fn do_clock_getres(clockid: ClockID) -> Result { + extern "C" { + fn occlum_ocall_clock_getres(clockid: clockid_t, res: *mut timespec_t) -> sgx_status_t; + } + + let mut res: timespec_t = Default::default(); + unsafe { + occlum_ocall_clock_getres(clockid as clockid_t, &mut res as *mut timespec_t); + } + let validate_resolution = |res: ×pec_t| -> Result<()> { + // The resolution can be ranged from 1 nanosecond to a few milliseconds + if res.sec == 0 && res.nsec > 0 && res.nsec < 1_000_000_000 { + Ok(()) + } else { + return_errno!(EINVAL, "invalid value for resolution"); + } + }; + // do sanity check + validate_resolution(&res).expect("ocall returned invalid resolution"); + Ok(res) +} + pub fn do_nanosleep(req: ×pec_t) -> Result<()> { extern "C" { fn occlum_ocall_nanosleep(req: *const timespec_t) -> sgx_status_t; diff --git a/src/pal/src/ocalls/time.c b/src/pal/src/ocalls/time.c index af670dd6..c8e852e8 100644 --- a/src/pal/src/ocalls/time.c +++ b/src/pal/src/ocalls/time.c @@ -10,6 +10,10 @@ void occlum_ocall_clock_gettime(int clockid, struct timespec *tp) { clock_gettime(clockid, tp); } +void occlum_ocall_clock_getres(int clockid, struct timespec *res) { + clock_getres(clockid, res); +} + void occlum_ocall_nanosleep(const struct timespec *req) { nanosleep(req, NULL); } diff --git a/test/time/main.c b/test/time/main.c index d7e1c53a..e3a31afa 100644 --- a/test/time/main.c +++ b/test/time/main.c @@ -29,6 +29,27 @@ int test_clock_gettime() { return 0; } +// ============================================================================ +// Test cases for clock_getres +// ============================================================================ + +int test_clock_getres() { + struct timespec res; + if (clock_getres(CLOCK_REALTIME, &res)) { + THROW_ERROR("clock_getres(CLOCK_REALTIME, ...) failed"); + } + if (clock_getres(CLOCK_MONOTONIC, &res)) { + THROW_ERROR("clock_getres(CLOCK_MONOTONIC, ...) failed"); + } + if (clock_getres(CLOCK_MONOTONIC_COARSE, &res)) { + THROW_ERROR("clock_getres(CLOCK_MONOTONIC_COARSE, ...) failed"); + } + if (clock_getres(CLOCK_REALTIME, NULL)) { + THROW_ERROR("clock_getres(CLOCK_REALTIME, NULL) failed"); + } + return 0; +} + // ============================================================================ // Test suite // ============================================================================ @@ -36,6 +57,7 @@ int test_clock_gettime() { static test_case_t test_cases[] = { TEST_CASE(test_gettimeofday), TEST_CASE(test_clock_gettime), + TEST_CASE(test_clock_getres), }; int main() {