aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/compat/freebsd32/freebsd32_misc.c34
-rw-r--r--sys/compat/freebsd32/syscalls.master5
-rw-r--r--sys/kern/kern_time.c138
-rw-r--r--sys/kern/syscalls.master4
-rw-r--r--sys/sys/syscallsubr.h2
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);