diff options
Diffstat (limited to 'sys')
| -rw-r--r-- | sys/compat/freebsd32/freebsd32_misc.c | 34 | ||||
| -rw-r--r-- | sys/compat/freebsd32/syscalls.master | 5 | ||||
| -rw-r--r-- | sys/kern/kern_time.c | 138 | ||||
| -rw-r--r-- | sys/kern/syscalls.master | 4 | ||||
| -rw-r--r-- | sys/sys/syscallsubr.h | 2 |
5 files changed, 145 insertions, 38 deletions
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c index 86b1399a98c0..08a072fbfa20 100644 --- a/sys/compat/freebsd32/freebsd32_misc.c +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -129,6 +129,8 @@ CTASSERT(sizeof(struct sigaction32) == 24); static int freebsd32_kevent_copyout(void *arg, struct kevent *kevp, int count); static int freebsd32_kevent_copyin(void *arg, struct kevent *kevp, int count); +static int freebsd32_user_clock_nanosleep(struct thread *td, clockid_t clock_id, + int flags, const struct timespec32 *ua_rqtp, struct timespec32 *ua_rmtp); void freebsd32_rusage_out(const struct rusage *s, struct rusage32 *s32) @@ -2226,28 +2228,48 @@ ofreebsd32_sigstack(struct thread *td, int freebsd32_nanosleep(struct thread *td, struct freebsd32_nanosleep_args *uap) { + + return (freebsd32_user_clock_nanosleep(td, CLOCK_REALTIME, + TIMER_RELTIME, uap->rqtp, uap->rmtp)); +} + +int +freebsd32_clock_nanosleep(struct thread *td, + struct freebsd32_clock_nanosleep_args *uap) +{ + int error; + + error = freebsd32_user_clock_nanosleep(td, uap->clock_id, uap->flags, + uap->rqtp, uap->rmtp); + return (kern_posix_error(td, error)); +} + +static int +freebsd32_user_clock_nanosleep(struct thread *td, clockid_t clock_id, + int flags, const struct timespec32 *ua_rqtp, struct timespec32 *ua_rmtp) +{ struct timespec32 rmt32, rqt32; struct timespec rmt, rqt; int error; - error = copyin(uap->rqtp, &rqt32, sizeof(rqt32)); + error = copyin(ua_rqtp, &rqt32, sizeof(rqt32)); if (error) return (error); CP(rqt32, rqt, tv_sec); CP(rqt32, rqt, tv_nsec); - if (uap->rmtp && - !useracc((caddr_t)uap->rmtp, sizeof(rmt), VM_PROT_WRITE)) + if (ua_rmtp != NULL && (flags & TIMER_ABSTIME) == 0 && + !useracc(ua_rmtp, sizeof(rmt32), VM_PROT_WRITE)) return (EFAULT); - error = kern_nanosleep(td, &rqt, &rmt); - if (error == EINTR && uap->rmtp) { + error = kern_clock_nanosleep(td, clock_id, flags, &rqt, &rmt); + if (error == EINTR && ua_rmtp != NULL && (flags & TIMER_ABSTIME) == 0) { int error2; CP(rmt, rmt32, tv_sec); CP(rmt, rmt32, tv_nsec); - error2 = copyout(&rmt32, uap->rmtp, sizeof(rmt32)); + error2 = copyout(&rmt32, ua_rmtp, sizeof(rmt32)); if (error2) error = error2; } diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master index 99a5a4e84098..723fbe6e4b67 100644 --- a/sys/compat/freebsd32/syscalls.master +++ b/sys/compat/freebsd32/syscalls.master @@ -462,7 +462,10 @@ struct ffclock_estimate *cest); } 243 AUE_NULL NOPROTO { int ffclock_getestimate( \ struct ffclock_estimate *cest); } -244 AUE_NULL UNIMPL nosys +244 AUE_NULL STD { int freebsd32_clock_nanosleep( \ + clockid_t clock_id, int flags, \ + const struct timespec32 *rqtp, \ + struct timespec32 *rmtp); } 245 AUE_NULL UNIMPL nosys 246 AUE_NULL UNIMPL nosys 247 AUE_NULL STD { int freebsd32_clock_getcpuclockid2(\ diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c index d31c12168fc9..92672438253a 100644 --- a/sys/kern/kern_time.c +++ b/sys/kern/kern_time.c @@ -86,6 +86,9 @@ static uma_zone_t itimer_zone = NULL; static int settime(struct thread *, struct timeval *); static void timevalfix(struct timeval *); +static int user_clock_nanosleep(struct thread *td, clockid_t clock_id, + int flags, const struct timespec *ua_rqtp, + struct timespec *ua_rmtp); static void itimer_start(void); static int itimer_init(void *, int, int); @@ -481,47 +484,95 @@ kern_clock_getres(struct thread *td, clockid_t clock_id, struct timespec *ts) return (0); } +int +kern_nanosleep(struct thread *td, struct timespec *rqt, struct timespec *rmt) +{ + + return (kern_clock_nanosleep(td, CLOCK_REALTIME, TIMER_RELTIME, rqt, + rmt)); +} + static uint8_t nanowait[MAXCPU]; int -kern_nanosleep(struct thread *td, struct timespec *rqt, struct timespec *rmt) +kern_clock_nanosleep(struct thread *td, clockid_t clock_id, int flags, + const struct timespec *rqt, struct timespec *rmt) { - struct timespec ts; + struct timespec ts, now; sbintime_t sbt, sbtt, prec, tmp; time_t over; int error; + bool is_abs_real; if (rqt->tv_nsec < 0 || rqt->tv_nsec >= 1000000000) return (EINVAL); - if (rqt->tv_sec < 0 || (rqt->tv_sec == 0 && rqt->tv_nsec == 0)) - return (0); - ts = *rqt; - if (ts.tv_sec > INT32_MAX / 2) { - over = ts.tv_sec - INT32_MAX / 2; - ts.tv_sec -= over; - } else - over = 0; - tmp = tstosbt(ts); - prec = tmp; - prec >>= tc_precexp; - if (TIMESEL(&sbt, tmp)) - sbt += tc_tick_sbt; - sbt += tmp; - error = tsleep_sbt(&nanowait[curcpu], PWAIT | PCATCH, "nanslp", - sbt, prec, C_ABSOLUTE); + if ((flags & ~TIMER_ABSTIME) != 0) + return (EINVAL); + switch (clock_id) { + case CLOCK_REALTIME: + case CLOCK_REALTIME_PRECISE: + case CLOCK_REALTIME_FAST: + case CLOCK_SECOND: + is_abs_real = (flags & TIMER_ABSTIME) != 0; + break; + case CLOCK_MONOTONIC: + case CLOCK_MONOTONIC_PRECISE: + case CLOCK_MONOTONIC_FAST: + case CLOCK_UPTIME: + case CLOCK_UPTIME_PRECISE: + case CLOCK_UPTIME_FAST: + is_abs_real = false; + break; + case CLOCK_VIRTUAL: + case CLOCK_PROF: + case CLOCK_PROCESS_CPUTIME_ID: + return (ENOTSUP); + case CLOCK_THREAD_CPUTIME_ID: + default: + return (EINVAL); + } + do { + ts = *rqt; + if ((flags & TIMER_ABSTIME) != 0) { + if (is_abs_real) + td->td_rtcgen = + atomic_load_acq_int(&rtc_generation); + error = kern_clock_gettime(td, clock_id, &now); + KASSERT(error == 0, ("kern_clock_gettime: %d", error)); + timespecsub(&ts, &now); + } + if (ts.tv_sec < 0 || (ts.tv_sec == 0 && ts.tv_nsec == 0)) { + error = EWOULDBLOCK; + break; + } + if (ts.tv_sec > INT32_MAX / 2) { + over = ts.tv_sec - INT32_MAX / 2; + ts.tv_sec -= over; + } else + over = 0; + tmp = tstosbt(ts); + prec = tmp; + prec >>= tc_precexp; + if (TIMESEL(&sbt, tmp)) + sbt += tc_tick_sbt; + sbt += tmp; + error = tsleep_sbt(&nanowait[curcpu], PWAIT | PCATCH, "nanslp", + sbt, prec, C_ABSOLUTE); + } while (error == 0 && is_abs_real && td->td_rtcgen == 0); + td->td_rtcgen = 0; if (error != EWOULDBLOCK) { + TIMESEL(&sbtt, tmp); + if (sbtt >= sbt) + return (0); if (error == ERESTART) error = EINTR; - TIMESEL(&sbtt, tmp); - if (rmt != NULL) { + if ((flags & TIMER_ABSTIME) == 0 && rmt != NULL) { ts = sbttots(sbt - sbtt); ts.tv_sec += over; if (ts.tv_sec < 0) timespecclear(&ts); *rmt = ts; } - if (sbtt >= sbt) - return (0); return (error); } return (0); @@ -537,21 +588,48 @@ struct nanosleep_args { int sys_nanosleep(struct thread *td, struct nanosleep_args *uap) { + + return (user_clock_nanosleep(td, CLOCK_REALTIME, TIMER_RELTIME, + uap->rqtp, uap->rmtp)); +} + +#ifndef _SYS_SYSPROTO_H_ +struct clock_nanosleep_args { + clockid_t clock_id; + int flags; + struct timespec *rqtp; + struct timespec *rmtp; +}; +#endif +/* ARGSUSED */ +int +sys_clock_nanosleep(struct thread *td, struct clock_nanosleep_args *uap) +{ + int error; + + error = user_clock_nanosleep(td, uap->clock_id, uap->flags, uap->rqtp, + uap->rmtp); + return (kern_posix_error(td, error)); +} + +static int +user_clock_nanosleep(struct thread *td, clockid_t clock_id, int flags, + const struct timespec *ua_rqtp, struct timespec *ua_rmtp) +{ struct timespec rmt, rqt; int error; - error = copyin(uap->rqtp, &rqt, sizeof(rqt)); + error = copyin(ua_rqtp, &rqt, sizeof(rqt)); if (error) return (error); - - if (uap->rmtp && - !useracc((caddr_t)uap->rmtp, sizeof(rmt), VM_PROT_WRITE)) - return (EFAULT); - error = kern_nanosleep(td, &rqt, &rmt); - if (error == EINTR && uap->rmtp) { + if (ua_rmtp != NULL && (flags & TIMER_ABSTIME) == 0 && + !useracc(ua_rmtp, sizeof(rmt), VM_PROT_WRITE)) + return (EFAULT); + error = kern_clock_nanosleep(td, clock_id, flags, &rqt, &rmt); + if (error == EINTR && ua_rmtp != NULL && (flags & TIMER_ABSTIME) == 0) { int error2; - error2 = copyout(&rmt, uap->rmtp, sizeof(rmt)); + error2 = copyout(&rmt, ua_rmtp, sizeof(rmt)); if (error2) error = error2; } diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 61b3ffac614f..75e91f36c950 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -461,7 +461,9 @@ struct ffclock_estimate *cest); } 243 AUE_NULL STD { int ffclock_getestimate( \ struct ffclock_estimate *cest); } -244 AUE_NULL UNIMPL nosys +244 AUE_NULL STD { int clock_nanosleep(clockid_t clock_id, \ + int flags, const struct timespec *rqtp, \ + struct timespec *rmtp); } 245 AUE_NULL UNIMPL nosys 246 AUE_NULL UNIMPL nosys 247 AUE_NULL STD { int clock_getcpuclockid2(id_t id,\ diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h index ef8326e01148..9a9dbe7d4247 100644 --- a/sys/sys/syscallsubr.h +++ b/sys/sys/syscallsubr.h @@ -82,6 +82,8 @@ int kern_clock_getres(struct thread *td, clockid_t clock_id, struct timespec *ts); int kern_clock_gettime(struct thread *td, clockid_t clock_id, struct timespec *ats); +int kern_clock_nanosleep(struct thread *td, clockid_t clock_id, int flags, + const struct timespec *rqtp, struct timespec *rmtp); int kern_clock_settime(struct thread *td, clockid_t clock_id, struct timespec *ats); int kern_close(struct thread *td, int fd); |
