diff options
| author | 2013-10-25 04:51:38 +0000 | |
|---|---|---|
| committer | 2013-10-25 04:51:38 +0000 | |
| commit | 086a9a62da816c7a4a5ad1ce34e32ee5963280f5 (patch) | |
| tree | df3f53e1f9847ab9e9c25fc5d590f7df6dde817e /sys/compat/linux/linux_time.c | |
| parent | Move the declarations for dogetrusage(), itimerround(), and dowait4() (diff) | |
| download | wireguard-openbsd-086a9a62da816c7a4a5ad1ce34e32ee5963280f5.tar.xz wireguard-openbsd-086a9a62da816c7a4a5ad1ce34e32ee5963280f5.zip | |
Start to deal with the time_t change's effect on compat/linux:
- add Linux versions of struct rusage, timeval, and itimerval and
conversion functions for them
- add Linux versions of getrusage(), gettimeofday(), {set,get}itimer(),
and nanosleep()
- fix various inconsistencies in naming of Linux versions of types
and conversion functions
- add mappings for LINUX_CLOCK_{PROCESS,THREAD}_CPUTIME_ID to the
native versions
Originally written months ago as part of the time_t work; long
memory, prodding, and ok from pirofti@
Diffstat (limited to 'sys/compat/linux/linux_time.c')
| -rw-r--r-- | sys/compat/linux/linux_time.c | 244 |
1 files changed, 223 insertions, 21 deletions
diff --git a/sys/compat/linux/linux_time.c b/sys/compat/linux/linux_time.c index 5f66d7d3da8..f60a2ff6926 100644 --- a/sys/compat/linux/linux_time.c +++ b/sys/compat/linux/linux_time.c @@ -1,4 +1,4 @@ -/* $OpenBSD: linux_time.c,v 1.4 2013/05/10 10:31:16 pirofti Exp $ */ +/* $OpenBSD: linux_time.c,v 1.5 2013/10/25 04:51:39 guenther Exp $ */ /* * Copyright (c) 2010, 2011 Paul Irofti <pirofti@openbsd.org> * @@ -23,6 +23,7 @@ #include <sys/time.h> #include <sys/systm.h> #include <sys/proc.h> +#include <sys/kernel.h> #include <sys/syscallargs.h> @@ -43,11 +44,10 @@ #define LINUX_CLOCK_MONOTONIC 1 #define LINUX_CLOCK_PROCESS_CPUTIME_ID 2 #define LINUX_CLOCK_THREAD_CPUTIME_ID 3 -#define LINUX_CLOCK_REALTIME_HR 4 -#define LINUX_CLOCK_MONOTONIC_HR 5 + int -native_to_linux_timespec(struct l_timespec *ltp, struct timespec *ntp) +bsd_to_linux_timespec(struct linux_timespec *ltp, const struct timespec *ntp) { if (ntp->tv_sec > LINUX_TIME_MAX) return EOVERFLOW; @@ -57,14 +57,34 @@ native_to_linux_timespec(struct l_timespec *ltp, struct timespec *ntp) } void -linux_to_native_timespec(struct timespec *ntp, struct l_timespec *ltp) +linux_to_bsd_timespec(struct timespec *ntp, const struct linux_timespec *ltp) { ntp->tv_sec = ltp->tv_sec; ntp->tv_nsec = ltp->tv_nsec; } int -linux_to_native_clockid(clockid_t *n, clockid_t l) +bsd_to_linux_itimerval(struct linux_itimerval *ltp, + const struct itimerval *ntp) +{ + int error; + + error = bsd_to_linux_timeval(<p->it_interval, &ntp->it_interval); + if (error) + return (error); + return (bsd_to_linux_timeval(<p->it_value, &ntp->it_value)); +} + +void +linux_to_bsd_itimerval(struct itimerval *ntp, + const struct linux_itimerval *ltp) +{ + linux_to_bsd_timeval(&ntp->it_interval, <p->it_interval); + linux_to_bsd_timeval(&ntp->it_value, <p->it_value); +} + +int +linux_to_bsd_clockid(clockid_t *n, clockid_t l) { switch (l) { case LINUX_CLOCK_REALTIME: @@ -74,9 +94,11 @@ linux_to_native_clockid(clockid_t *n, clockid_t l) *n = CLOCK_MONOTONIC; break; case LINUX_CLOCK_PROCESS_CPUTIME_ID: + *n = CLOCK_PROCESS_CPUTIME_ID; + break; case LINUX_CLOCK_THREAD_CPUTIME_ID: - case LINUX_CLOCK_REALTIME_HR: - case LINUX_CLOCK_MONOTONIC_HR: + *n = CLOCK_THREAD_CPUTIME_ID; + break; default: return (EINVAL); break; @@ -89,35 +111,34 @@ int linux_sys_clock_getres(struct proc *p, void *v, register_t *retval) { struct linux_sys_clock_getres_args *uap = v; - struct sys_clock_getres_args cgr; - + struct linux_timespec ltp; + clockid_t clockid; int error; if (SCARG(uap, tp) == NULL) return 0; - error = linux_to_native_clockid(&SCARG(&cgr, clock_id), - SCARG(uap, which)); + error = linux_to_bsd_clockid(&clockid, SCARG(uap, which)); if (error != 0) return error; - SCARG(&cgr, tp) = (struct timespec *)SCARG(uap, tp); - return sys_clock_getres(p, &cgr, retval); + /* ahhh, just give a good guess */ + ltp.tv_sec = 0; + ltp.tv_nsec = 1000000000 / hz; + + return (copyout(<p, SCARG(uap, tp), sizeof ltp)); } int linux_sys_clock_gettime(struct proc *p, void *v, register_t *retval) { struct linux_sys_clock_gettime_args *uap = v; - - clockid_t clockid = 0; - struct timespec tp; - struct l_timespec ltp; - + struct linux_timespec ltp; + clockid_t clockid; int error; - error = linux_to_native_clockid(&clockid, SCARG(uap, which)); + error = linux_to_bsd_clockid(&clockid, SCARG(uap, which)); if (error != 0) return error; @@ -125,9 +146,190 @@ linux_sys_clock_gettime(struct proc *p, void *v, register_t *retval) if (error != 0) return error; - error = native_to_linux_timespec(<p, &tp); + error = bsd_to_linux_timespec(<p, &tp); if (error != 0) return error; return (copyout(<p, SCARG(uap, tp), sizeof ltp)); } + +int +linux_sys_nanosleep(struct proc *p, void *v, register_t *retval) +{ + static int nanowait; + struct linux_sys_nanosleep_args /* { + syscallarg(const struct linux_timespec *) rqtp; + syscallarg(struct linux_timespec *) rmtp; + } */ *uap = v; + struct linux_timespec lts; + struct timespec rqt, rmt; + struct timespec sts, ets; + struct linux_timespec *rmtp; + struct timeval tv; + int error, error1; + + rmtp = SCARG(uap, rmtp); + error = copyin(SCARG(uap, rqtp), <s, sizeof(lts)); + if (error) + return (error); + linux_to_bsd_timespec(&rqt, <s); + + TIMESPEC_TO_TIMEVAL(&tv, &rqt); + if (itimerfix(&tv)) + return (EINVAL); + + if (rmtp) + getnanouptime(&sts); + + error = tsleep(&nanowait, PWAIT | PCATCH, "nanosleep", + MAX(1, tvtohz(&tv))); + if (error == ERESTART) + error = EINTR; + if (error == EWOULDBLOCK) + error = 0; + + if (rmtp) { + getnanouptime(&ets); + + timespecsub(&ets, &sts, &sts); + timespecsub(&rqt, &sts, &rmt); + + if (rmt.tv_sec < 0) + timespecclear(&rmt); + + if ((error1 = bsd_to_linux_timespec(<s, &rmt)) || + (error1 = copyout(<s, rmtp, sizeof(lts)))) + error = error1; + } + + return error; +} + +int +linux_sys_gettimeofday(struct proc *p, void *v, register_t *retval) +{ + struct linux_sys_gettimeofday_args /* { + syscallarg(struct linux_timeval *) tp; + syscallarg(struct timezone *) tzp; + } */ *uap = v; + struct timeval atv; + struct linux_timeval latv; + struct linux_timeval *tp; + struct timezone *tzp; + int error = 0; + + tp = SCARG(uap, tp); + tzp = SCARG(uap, tzp); + + if (tp) { + microtime(&atv); + if ((error = bsd_to_linux_timeval(&latv, &atv)) || + (error = copyout(&latv, tp, sizeof (latv)))) + return (error); + } + if (tzp) + error = copyout(&tz, tzp, sizeof (tz)); + return (error); +} + +int +linux_sys_getitimer(struct proc *p, void *v, register_t *retval) +{ + struct linux_sys_getitimer_args /* { + syscallarg(int) which; + syscallarg(struct linux_itimerval *) itv; + } */ *uap = v; + struct itimerval aitv; + struct linux_itimerval laitv; + int s, which, error; + + which = SCARG(uap, which); + + if (which < ITIMER_REAL || which > ITIMER_PROF) + return (EINVAL); + s = splclock(); + aitv = p->p_p->ps_timer[which]; + + if (which == ITIMER_REAL) { + struct timeval now; + + getmicrouptime(&now); + /* + * Convert from absolute to relative time in .it_value + * part of real time timer. If time for real time timer + * has passed return 0, else return difference between + * current time and time for the timer to go off. + */ + if (timerisset(&aitv.it_value)) { + if (timercmp(&aitv.it_value, &now, <)) + timerclear(&aitv.it_value); + else + timersub(&aitv.it_value, &now, + &aitv.it_value); + } + } + splx(s); + if ((error = bsd_to_linux_itimerval(&laitv, &aitv))) + return error; + return (copyout(&laitv, SCARG(uap, itv), sizeof(laitv))); +} + +int +linux_sys_setitimer(struct proc *p, void *v, register_t *retval) +{ + struct linux_sys_setitimer_args /* { + syscallarg(int) which; + syscallarg(const struct linux_itimerval *) itv; + syscallarg(struct linux_itimerval *) oitv; + } */ *uap = v; + struct linux_sys_getitimer_args getargs; + struct itimerval aitv; + struct linux_itimerval laitv; + const struct linux_itimerval *itvp; + struct linux_itimerval *oitv; + struct process *pr = p->p_p; + int error; + int timo; + int which; + + which = SCARG(uap, which); + itvp = SCARG(uap, itv); + oitv = SCARG(uap, oitv); + + if (which < ITIMER_REAL || which > ITIMER_PROF) + return (EINVAL); + if (itvp && (error = copyin(itvp, &laitv, sizeof(laitv)))) + return (error); + if (oitv != NULL) { + SCARG(&getargs, which) = which; + SCARG(&getargs, itv) = oitv; + if ((error = linux_sys_getitimer(p, &getargs, retval))) + return (error); + } + if (itvp == 0) + return (0); + linux_to_bsd_itimerval(&aitv, &laitv); + if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval)) + return (EINVAL); + if (which == ITIMER_REAL) { + struct timeval ctv; + + timeout_del(&pr->ps_realit_to); + getmicrouptime(&ctv); + if (timerisset(&aitv.it_value)) { + timo = tvtohz(&aitv.it_value); + timeout_add(&pr->ps_realit_to, timo); + timeradd(&aitv.it_value, &ctv, &aitv.it_value); + } + pr->ps_timer[ITIMER_REAL] = aitv; + } else { + int s; + + itimerround(&aitv.it_interval); + s = splclock(); + pr->ps_timer[which] = aitv; + splx(s); + } + + return (0); +} |
