summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/kern/kern_time.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2017-04-04 09:36:57 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2017-04-04 14:46:23 +0200
commitde8a76da2f374792594ce03a203b3f30e4889f6f (patch)
tree12b5e1e59358005c3c522955c08aee4795e4829c /freebsd/sys/kern/kern_time.c
parentEnable bridging by default (diff)
downloadrtems-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.c145
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;
}