diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2017-04-04 09:36:57 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2017-04-04 14:46:23 +0200 |
commit | de8a76da2f374792594ce03a203b3f30e4889f6f (patch) | |
tree | 12b5e1e59358005c3c522955c08aee4795e4829c /freebsd/sys/kern/kern_time.c | |
parent | Enable bridging by default (diff) | |
download | rtems-libbsd-de8a76da2f374792594ce03a203b3f30e4889f6f.tar.bz2 |
Update to FreeBSD head 2017-04-04
Git mirror commit 642b174daddbd0efd9bb5f242c43f4ab4db6869f.
Diffstat (limited to 'freebsd/sys/kern/kern_time.c')
-rw-r--r-- | freebsd/sys/kern/kern_time.c | 145 |
1 files changed, 115 insertions, 30 deletions
diff --git a/freebsd/sys/kern/kern_time.c b/freebsd/sys/kern/kern_time.c index 95111932..2fc7092f 100644 --- a/freebsd/sys/kern/kern_time.c +++ b/freebsd/sys/kern/kern_time.c @@ -90,6 +90,9 @@ static uma_zone_t itimer_zone = NULL; static int settime(struct thread *, struct timeval *); #endif /* __rtems__ */ 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); #ifndef __rtems__ static void itimer_start(void); @@ -397,6 +400,11 @@ sys_clock_settime(struct thread *td, struct clock_settime_args *uap) return (kern_clock_settime(td, uap->clock_id, &ats)); } +static int allow_insane_settime = 0; +SYSCTL_INT(_debug, OID_AUTO, allow_insane_settime, CTLFLAG_RWTUN, + &allow_insane_settime, 0, + "do not perform possibly restrictive checks on settime(2) args"); + int kern_clock_settime(struct thread *td, clockid_t clock_id, struct timespec *ats) { @@ -410,6 +418,8 @@ kern_clock_settime(struct thread *td, clockid_t clock_id, struct timespec *ats) if (ats->tv_nsec < 0 || ats->tv_nsec >= 1000000000 || ats->tv_sec < 0) return (EINVAL); + if (!allow_insane_settime && ats->tv_sec > 9999ULL * 366 * 24 * 60 * 60) + return (EINVAL); /* XXX Don't convert nsec->usec and back */ TIMESPEC_TO_TIMEVAL(&atv, ats); error = settime(td, &atv); @@ -487,47 +497,95 @@ kern_clock_getres(struct thread *td, clockid_t clock_id, struct timespec *ts) } #endif +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); @@ -543,21 +601,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 && 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; } |