aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorEric van Gyzen <vangyzen@FreeBSD.org>2017-03-19 00:51:12 +0000
committerEric van Gyzen <vangyzen@FreeBSD.org>2017-03-19 00:51:12 +0000
commit3f8455b0905a05552b1155e09165787e1d098060 (patch)
tree7e464dbfe7b8012fa2a68d9d0a7b2d3a07b11df3 /sys
parenta776eeafdcaae027734542d69612d35971b55c1c (diff)
Add clock_nanosleep()
Add a clock_nanosleep() syscall, as specified by POSIX. Make nanosleep() a wrapper around it. Attach the clock_nanosleep test from NetBSD. Adjust it for the FreeBSD behavior of updating rmtp only when interrupted by a signal. I believe this to be POSIX-compliant, since POSIX mentions the rmtp parameter only in the paragraph about EINTR. This is also what Linux does. (NetBSD updates rmtp unconditionally.) Copy the whole nanosleep.2 man page from NetBSD because it is complete and closely resembles the POSIX description. Edit, polish, and reword it a bit, being sure to keep any relevant text from the FreeBSD page. Reviewed by: kib, ngie, jilles MFC after: 3 weeks Relnotes: yes Sponsored by: Dell EMC Differential Revision: https://reviews.freebsd.org/D10020
Notes
svn path=/head/; revision=315526
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);