diff --git a/sys/compat/cloudabi/cloudabi_clock.c b/sys/compat/cloudabi/cloudabi_clock.c index a6b783c59117..8462f233b738 100644 --- a/sys/compat/cloudabi/cloudabi_clock.c +++ b/sys/compat/cloudabi/cloudabi_clock.c @@ -26,22 +26,100 @@ #include __FBSDID("$FreeBSD$"); +#include +#include +#include +#include + #include +#include +#include + +/* Converts a CloudABI clock ID to a FreeBSD clock ID. */ +static int +cloudabi_convert_clockid(cloudabi_clockid_t in, clockid_t *out) +{ + switch (in) { + case CLOUDABI_CLOCK_MONOTONIC: + *out = CLOCK_MONOTONIC; + return (0); + case CLOUDABI_CLOCK_PROCESS_CPUTIME_ID: + *out = CLOCK_PROCESS_CPUTIME_ID; + return (0); + case CLOUDABI_CLOCK_REALTIME: + *out = CLOCK_REALTIME; + return (0); + case CLOUDABI_CLOCK_THREAD_CPUTIME_ID: + *out = CLOCK_THREAD_CPUTIME_ID; + return (0); + default: + return (EINVAL); + } +} + +/* Converts a struct timespec to a CloudABI timestamp. */ +int +cloudabi_convert_timespec(const struct timespec *in, cloudabi_timestamp_t *out) +{ + cloudabi_timestamp_t s, ns; + + if (in->tv_sec < 0) { + /* Timestamps from before the Epoch cannot be expressed. */ + *out = 0; + return (EOVERFLOW); + } + s = in->tv_sec; + ns = in->tv_nsec; + if (s > UINT64_MAX / 1000000000 || + (s == UINT64_MAX / 1000000000 && ns > UINT64_MAX % 1000000000)) { + /* Addition of seconds and nanoseconds would overflow. */ + *out = UINT64_MAX; + return (EOVERFLOW); + } + *out = s * 1000000000 + ns; + return (0); +} int cloudabi_sys_clock_res_get(struct thread *td, struct cloudabi_sys_clock_res_get_args *uap) { + struct timespec ts; + cloudabi_timestamp_t cts; + int error; + clockid_t clockid; - /* Not implemented. */ - return (ENOSYS); + error = cloudabi_convert_clockid(uap->clock_id, &clockid); + if (error != 0) + return (error); + error = kern_clock_getres(td, clockid, &ts); + if (error != 0) + return (error); + error = cloudabi_convert_timespec(&ts, &cts); + if (error != 0) + return (error); + td->td_retval[0] = cts; + return (0); } int cloudabi_sys_clock_time_get(struct thread *td, struct cloudabi_sys_clock_time_get_args *uap) { + struct timespec ts; + cloudabi_timestamp_t cts; + int error; + clockid_t clockid; - /* Not implemented. */ - return (ENOSYS); + error = cloudabi_convert_clockid(uap->clock_id, &clockid); + if (error != 0) + return (error); + error = kern_clock_gettime(td, clockid, &ts); + if (error != 0) + return (error); + error = cloudabi_convert_timespec(&ts, &cts); + if (error != 0) + return (error); + td->td_retval[0] = cts; + return (0); } diff --git a/sys/compat/cloudabi/cloudabi_util.h b/sys/compat/cloudabi/cloudabi_util.h index 4389e3de4592..d9e6f127eb97 100644 --- a/sys/compat/cloudabi/cloudabi_util.h +++ b/sys/compat/cloudabi/cloudabi_util.h @@ -30,7 +30,12 @@ #include +struct timespec; + /* Converts a FreeBSD errno to a CloudABI errno. */ cloudabi_errno_t cloudabi_convert_errno(int); +/* Converts a struct timespec to a CloudABI timestamp. */ +int cloudabi_convert_timespec(const struct timespec *, cloudabi_timestamp_t *); + #endif