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
This commit is contained in:
vangyzen 2017-03-19 00:51:12 +00:00
parent 3b61da190e
commit d6de25428d
19 changed files with 367 additions and 83 deletions

View File

@ -46,7 +46,11 @@ ATF_TC_BODY(clock_nanosleep_remain, tc)
rqtp.tv_sec = 0; rqtp.tv_nsec = 0; rqtp.tv_sec = 0; rqtp.tv_nsec = 0;
rmtp.tv_sec = -1; rmtp.tv_nsec = -1; rmtp.tv_sec = -1; rmtp.tv_nsec = -1;
ATF_REQUIRE(clock_nanosleep(CLOCK_REALTIME, 0, &rqtp, &rmtp) == 0); ATF_REQUIRE(clock_nanosleep(CLOCK_REALTIME, 0, &rqtp, &rmtp) == 0);
#ifdef __FreeBSD__
ATF_CHECK(rmtp.tv_sec == -1 && rmtp.tv_nsec == -1);
#else
ATF_CHECK(rmtp.tv_sec == 0 && rmtp.tv_nsec == 0); ATF_CHECK(rmtp.tv_sec == 0 && rmtp.tv_nsec == 0);
#endif
ATF_REQUIRE(clock_gettime(CLOCK_REALTIME, &rqtp) == 0); ATF_REQUIRE(clock_gettime(CLOCK_REALTIME, &rqtp) == 0);
rmtp.tv_sec = -1; rmtp.tv_nsec = -1; rmtp.tv_sec = -1; rmtp.tv_nsec = -1;

View File

@ -169,12 +169,12 @@ void tzset(void);
int clock_getres(clockid_t, struct timespec *); int clock_getres(clockid_t, struct timespec *);
int clock_gettime(clockid_t, struct timespec *); int clock_gettime(clockid_t, struct timespec *);
int clock_settime(clockid_t, const struct timespec *); int clock_settime(clockid_t, const struct timespec *);
/* XXX missing: clock_nanosleep() */
int nanosleep(const struct timespec *, struct timespec *); int nanosleep(const struct timespec *, struct timespec *);
#endif /* __POSIX_VISIBLE >= 199309 */ #endif /* __POSIX_VISIBLE >= 199309 */
#if __POSIX_VISIBLE >= 200112 #if __POSIX_VISIBLE >= 200112
int clock_getcpuclockid(pid_t, clockid_t *); int clock_getcpuclockid(pid_t, clockid_t *);
int clock_nanosleep(clockid_t, int, const struct timespec *, struct timespec *);
#endif #endif
#if __POSIX_VISIBLE >= 199506 #if __POSIX_VISIBLE >= 199506

View File

@ -229,6 +229,7 @@ enum {
INTERPOS_ppoll, INTERPOS_ppoll,
INTERPOS_map_stacks_exec, INTERPOS_map_stacks_exec,
INTERPOS_fdatasync, INTERPOS_fdatasync,
INTERPOS_clock_nanosleep,
INTERPOS_MAX INTERPOS_MAX
}; };
@ -318,6 +319,8 @@ int __sys_aio_suspend(const struct aiocb * const[], int,
int __sys_accept(int, struct sockaddr *, __socklen_t *); int __sys_accept(int, struct sockaddr *, __socklen_t *);
int __sys_accept4(int, struct sockaddr *, __socklen_t *, int); int __sys_accept4(int, struct sockaddr *, __socklen_t *, int);
int __sys_clock_gettime(__clockid_t, struct timespec *ts); int __sys_clock_gettime(__clockid_t, struct timespec *ts);
int __sys_clock_nanosleep(__clockid_t, int,
const struct timespec *, struct timespec *);
int __sys_close(int); int __sys_close(int);
int __sys_connect(int, const struct sockaddr *, __socklen_t); int __sys_connect(int, const struct sockaddr *, __socklen_t);
int __sys_fcntl(int, int, ...); int __sys_fcntl(int, int, ...);

View File

@ -56,6 +56,7 @@
#define bind _bind #define bind _bind
#define __cap_get_fd ___cap_get_fd #define __cap_get_fd ___cap_get_fd
#define __cap_set_fd ___cap_set_fd #define __cap_set_fd ___cap_set_fd
#define clock_nanosleep _clock_nanosleep
#define close _close #define close _close
#define connect _connect #define connect _connect
#define dup _dup #define dup _dup

View File

@ -37,6 +37,7 @@
#undef bind #undef bind
#undef __cap_get_fd #undef __cap_get_fd
#undef __cap_set_fd #undef __cap_set_fd
#undef clock_nanosleep
#undef close #undef close
#undef connect #undef connect
#undef dup #undef dup

View File

@ -45,6 +45,7 @@ INTERPOSED = \
accept \ accept \
accept4 \ accept4 \
aio_suspend \ aio_suspend \
clock_nanosleep \
close \ close \
connect \ connect \
fcntl \ fcntl \
@ -360,6 +361,7 @@ MLINKS+=chown.2 fchown.2 \
chown.2 lchown.2 chown.2 lchown.2
MLINKS+=clock_gettime.2 clock_getres.2 \ MLINKS+=clock_gettime.2 clock_getres.2 \
clock_gettime.2 clock_settime.2 clock_gettime.2 clock_settime.2
MLINKS+=nanosleep.2 clock_nanosleep.2
MLINKS+=cpuset.2 cpuset_getid.2 \ MLINKS+=cpuset.2 cpuset_getid.2 \
cpuset.2 cpuset_setid.2 cpuset.2 cpuset_setid.2
MLINKS+=cpuset_getaffinity.2 cpuset_setaffinity.2 MLINKS+=cpuset_getaffinity.2 cpuset_setaffinity.2

View File

@ -399,6 +399,7 @@ FBSD_1.4 {
}; };
FBSD_1.5 { FBSD_1.5 {
clock_nanosleep;
fdatasync; fdatasync;
}; };
@ -511,6 +512,7 @@ FBSDprivate_1.0 {
__sys_clock_getres; __sys_clock_getres;
_clock_gettime; _clock_gettime;
__sys_clock_gettime; __sys_clock_gettime;
__sys_clock_nanosleep;
_clock_settime; _clock_settime;
__sys_clock_settime; __sys_clock_settime;
_close; _close;

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2017 Eric van Gyzen
* Copyright (c) 2014 The FreeBSD Foundation.
* All rights reserved.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <time.h>
#include "libc_private.h"
__weak_reference(__sys_clock_nanosleep, __clock_nanosleep);
#pragma weak clock_nanosleep
int
clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *rqtp,
struct timespec *rmtp)
{
return (((int (*)(clockid_t, int, const struct timespec *,
struct timespec *))
__libc_interposing[INTERPOS_clock_nanosleep])(clock_id, flags,
rqtp, rmtp));
}

View File

@ -80,6 +80,7 @@ interpos_func_t __libc_interposing[INTERPOS_MAX] = {
SLOT(ppoll, __sys_ppoll), SLOT(ppoll, __sys_ppoll),
SLOT(map_stacks_exec, __libc_map_stacks_exec), SLOT(map_stacks_exec, __libc_map_stacks_exec),
SLOT(fdatasync, __sys_fdatasync), SLOT(fdatasync, __sys_fdatasync),
SLOT(clock_nanosleep, __sys_clock_nanosleep),
}; };
#undef SLOT #undef SLOT

View File

@ -1,5 +1,4 @@
.\" $OpenBSD: nanosleep.2,v 1.1 1997/04/20 20:56:20 tholo Exp $ .\" $NetBSD: nanosleep.2,v 1.23 2016/11/14 10:40:59 wiz Exp $
.\" $NetBSD: nanosleep.2,v 1.1 1997/04/17 18:12:02 jtc Exp $
.\" .\"
.\" Copyright (c) 1986, 1991, 1993 .\" Copyright (c) 1986, 1991, 1993
.\" The Regents of the University of California. All rights reserved. .\" The Regents of the University of California. All rights reserved.
@ -31,51 +30,136 @@
.\" @(#)sleep.3 8.1 (Berkeley) 6/4/93 .\" @(#)sleep.3 8.1 (Berkeley) 6/4/93
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd April 17, 1997 .Dd March 17, 2017
.Dt NANOSLEEP 2 .Dt NANOSLEEP 2
.Os .Os
.Sh NAME .Sh NAME
.Nm nanosleep .Nm nanosleep
.Nd suspend process execution for an interval measured in nanoseconds .Nd high resolution sleep
.Sh LIBRARY .Sh LIBRARY
.Lb libc .Lb libc
.Sh SYNOPSIS .Sh SYNOPSIS
.In time.h .In time.h
.Ft int .Ft int
.Fn nanosleep "const struct timespec *rqtp" "struct timespec *rmtp" .Fo clock_nanosleep
.Fa "clockid_t clock_id"
.Fa "int flags"
.Fa "const struct timespec *rqtp"
.Fa "struct timespec *rmtp"
.Fc
.Ft int
.Fo nanosleep
.Fa "const struct timespec *rqtp"
.Fa "struct timespec *rmtp"
.Fc
.Sh DESCRIPTION .Sh DESCRIPTION
The
.Fn nanosleep
system call
causes the calling thread to sleep until the time interval specified by
.Fa rqtp
has elapsed.
An unmasked signal will
cause it to terminate the sleep early, regardless of the
.Dv SA_RESTART
value on the interrupting signal.
.Sh RETURN VALUES
If the If the
.Fn nanosleep .Dv TIMER_ABSTIME
system call returns because the requested time has elapsed, the value flag is not set in the
returned will be zero. .Fa flags
argument, then
.Fn clock_nanosleep
suspends execution of the calling thread until either the
time interval specified by the
.Fa rqtp
argument has elapsed,
or a signal is delivered to the calling process and its
action is to invoke a signal-catching function or to terminate the
process.
The clock used to measure the time is specified by the
.Fa clock_id
argument.
.Pp .Pp
If the If the
.Dv TIMER_ABSTIME
flag is set in the
.Fa flags
argument, then
.Fn clock_nanosleep
suspends execution of the calling thread until either the value
of the clock specified by the
.Fa clock_id
argument reaches the absolute time specified by the
.Fa rqtp
argument,
or a signal is delivered to the calling process and its
action is to invoke a signal-catching function or to terminate the
process.
If, at the time of the call, the time value specified by
.Fa rqtp
is less than or equal to the time value of the specified clock, then
.Fn clock_nanosleep
returns immediately and the calling thread is not suspended.
.Pp
The suspension time may be longer than requested due to the
scheduling of other activity by the system.
An unmasked signal will terminate the sleep early, regardless of the
.Dv SA_RESTART
value on the interrupting signal.
The
.Fa rqtp
and
.Fa rmtp
arguments can point to the same object.
.Pp
The following
.Fa clock_id
values are supported:
.Pp
.Bl -item -compact -offset indent
.It
CLOCK_MONOTONIC
.It
CLOCK_MONOTONIC_FAST
.It
CLOCK_MONOTONIC_PRECISE
.It
CLOCK_REALTIME
.It
CLOCK_REALTIME_FAST
.It
CLOCK_REALTIME_PRECISE
.It
CLOCK_SECOND
.It
CLOCK_UPTIME
.It
CLOCK_UPTIME_FAST
.It
CLOCK_UPTIME_PRECISE
.El
.Pp
The
.Fn nanosleep .Fn nanosleep
system call returns due to the delivery of a signal, the value returned function behaves like
will be -1, and the global variable .Fn clock_nanosleep
with a
.Fa clock_id
argument of
.Dv CLOCK_REALTIME
and without the
.Dv TIMER_ABSTIME
flag in the
.Fa flags
argument.
.Sh RETURN VALUES
These functions return zero when the requested time has elapsed.
.Pp
If these functions return for any other reason, then
.Fn clock_nanosleep
will directly return the error number, and
.Fn nanosleep
will return \-1 with the global variable
.Va errno .Va errno
will be set to indicate the interruption. set to indicate the error.
If If a relative sleep is interrupted by a signal and
.Fa rmtp .Fa rmtp
is is
.No non- Ns Dv NULL , .Pf non- Dv NULL ,
the timespec structure it references is updated to contain the the timespec structure it references is updated to contain the
unslept amount (the request time minus the time actually slept). unslept amount (the request time minus the time actually slept).
.Sh ERRORS .Sh ERRORS
The These functions can fail with the following errors.
.Fn nanosleep
system call fails if:
.Bl -tag -width Er .Bl -tag -width Er
.It Bq Er EFAULT .It Bq Er EFAULT
Either Either
@ -85,27 +169,32 @@ or
points to memory that is not a valid part of the process points to memory that is not a valid part of the process
address space. address space.
.It Bq Er EINTR .It Bq Er EINTR
The The function was interrupted by the delivery of a signal.
.Fn nanosleep
system call
was interrupted by the delivery of a signal.
.It Bq Er EINVAL .It Bq Er EINVAL
The The
.Fa rqtp .Fa rqtp
argument argument specified a nanosecond value less than zero
specified a nanosecond value less than zero
or greater than or equal to 1000 million. or greater than or equal to 1000 million.
.It Bq Er ENOSYS .It Bq Er EINVAL
The The
.Fn nanosleep .Fa flags
system call argument contained an invalid flag.
is not supported by this implementation. .It Bq Er EINVAL
The
.Fa clock_id
argument was
.Dv CLOCK_THREAD_CPUTIME_ID
or an unrecognized value.
.It Bq Er ENOTSUP
The
.Fa clock_id
argument was valid but not supported by this implementation of
.Fn clock_nanosleep .
.El .El
.Sh SEE ALSO .Sh SEE ALSO
.Xr sigsuspend 2 , .Xr clock_gettime 2 ,
.Xr sigaction 2 ,
.Xr sleep 3 .Xr sleep 3
.Sh STANDARDS .Sh STANDARDS
The These functions conform to
.Fn nanosleep .St -p1003.1-2008 .
system call conforms to
.St -p1003.1b-93 .

View File

@ -12,6 +12,7 @@ NETBSD_ATF_TESTS_C+= access_test
NETBSD_ATF_TESTS_C+= bind_test NETBSD_ATF_TESTS_C+= bind_test
NETBSD_ATF_TESTS_C+= chroot_test NETBSD_ATF_TESTS_C+= chroot_test
NETBSD_ATF_TESTS_C+= clock_gettime_test NETBSD_ATF_TESTS_C+= clock_gettime_test
NETBSD_ATF_TESTS_C+= clock_nanosleep_test
NETBSD_ATF_TESTS_C+= connect_test NETBSD_ATF_TESTS_C+= connect_test
NETBSD_ATF_TESTS_C+= dup_test NETBSD_ATF_TESTS_C+= dup_test
NETBSD_ATF_TESTS_C+= fsync_test NETBSD_ATF_TESTS_C+= fsync_test

View File

@ -865,6 +865,8 @@ int __sys_sigwaitinfo(const sigset_t *set, siginfo_t *info);
/* #include <time.h> */ /* #include <time.h> */
#ifdef _TIME_H_ #ifdef _TIME_H_
int __sys_clock_nanosleep(clockid_t, int, const struct timespec *,
struct timespec *);
int __sys_nanosleep(const struct timespec *, struct timespec *); int __sys_nanosleep(const struct timespec *, struct timespec *);
#endif #endif

View File

@ -259,6 +259,22 @@ __thr_msync(void *addr, size_t len, int flags)
return (ret); return (ret);
} }
static int
__thr_clock_nanosleep(clockid_t clock_id, int flags,
const struct timespec *time_to_sleep, struct timespec *time_remaining)
{
struct pthread *curthread;
int ret;
curthread = _get_curthread();
_thr_cancel_enter(curthread);
ret = __sys_clock_nanosleep(clock_id, flags, time_to_sleep,
time_remaining);
_thr_cancel_leave(curthread, 1);
return (ret);
}
static int static int
__thr_nanosleep(const struct timespec *time_to_sleep, __thr_nanosleep(const struct timespec *time_to_sleep,
struct timespec *time_remaining) struct timespec *time_remaining)
@ -668,6 +684,7 @@ __thr_interpose_libc(void)
SLOT(ppoll); SLOT(ppoll);
SLOT(map_stacks_exec); SLOT(map_stacks_exec);
SLOT(fdatasync); SLOT(fdatasync);
SLOT(clock_nanosleep);
#undef SLOT #undef SLOT
*(__libc_interposing_slot( *(__libc_interposing_slot(
INTERPOS__pthread_mutex_init_calloc_cb)) = INTERPOS__pthread_mutex_init_calloc_cb)) =

View File

@ -1,5 +1,5 @@
.\" $FreeBSD$ .\" $FreeBSD$
.Dd February 17, 2017 .Dd March 18, 2017
.Dt PTHREAD_TESTCANCEL 3 .Dt PTHREAD_TESTCANCEL 3
.Os .Os
.Sh NAME .Sh NAME
@ -105,6 +105,7 @@ functions:
.It Fn accept4 .It Fn accept4
.It Fn aio_suspend .It Fn aio_suspend
.It Fn connect .It Fn connect
.It Fn clock_nanosleep
.It Fn close .It Fn close
.It Fn creat .It Fn creat
.It Fn fcntl .It Fn fcntl

View File

@ -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_copyout(void *arg, struct kevent *kevp, int count);
static int freebsd32_kevent_copyin(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 void
freebsd32_rusage_out(const struct rusage *s, struct rusage32 *s32) freebsd32_rusage_out(const struct rusage *s, struct rusage32 *s32)
@ -2225,29 +2227,49 @@ ofreebsd32_sigstack(struct thread *td,
int int
freebsd32_nanosleep(struct thread *td, struct freebsd32_nanosleep_args *uap) 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 timespec32 rmt32, rqt32;
struct timespec rmt, rqt; struct timespec rmt, rqt;
int error; int error;
error = copyin(uap->rqtp, &rqt32, sizeof(rqt32)); error = copyin(ua_rqtp, &rqt32, sizeof(rqt32));
if (error) if (error)
return (error); return (error);
CP(rqt32, rqt, tv_sec); CP(rqt32, rqt, tv_sec);
CP(rqt32, rqt, tv_nsec); CP(rqt32, rqt, tv_nsec);
if (uap->rmtp && if (ua_rmtp != NULL && (flags & TIMER_ABSTIME) == 0 &&
!useracc((caddr_t)uap->rmtp, sizeof(rmt), VM_PROT_WRITE)) !useracc(ua_rmtp, sizeof(rmt32), VM_PROT_WRITE))
return (EFAULT); return (EFAULT);
error = kern_nanosleep(td, &rqt, &rmt); error = kern_clock_nanosleep(td, clock_id, flags, &rqt, &rmt);
if (error == EINTR && uap->rmtp) { if (error == EINTR && ua_rmtp != NULL && (flags & TIMER_ABSTIME) == 0) {
int error2; int error2;
CP(rmt, rmt32, tv_sec); CP(rmt, rmt32, tv_sec);
CP(rmt, rmt32, tv_nsec); CP(rmt, rmt32, tv_nsec);
error2 = copyout(&rmt32, uap->rmtp, sizeof(rmt32)); error2 = copyout(&rmt32, ua_rmtp, sizeof(rmt32));
if (error2) if (error2)
error = error2; error = error2;
} }

View File

@ -462,7 +462,10 @@
struct ffclock_estimate *cest); } struct ffclock_estimate *cest); }
243 AUE_NULL NOPROTO { int ffclock_getestimate( \ 243 AUE_NULL NOPROTO { int ffclock_getestimate( \
struct ffclock_estimate *cest); } 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 245 AUE_NULL UNIMPL nosys
246 AUE_NULL UNIMPL nosys 246 AUE_NULL UNIMPL nosys
247 AUE_NULL STD { int freebsd32_clock_getcpuclockid2(\ 247 AUE_NULL STD { int freebsd32_clock_getcpuclockid2(\

View File

@ -86,6 +86,9 @@ static uma_zone_t itimer_zone = NULL;
static int settime(struct thread *, struct timeval *); static int settime(struct thread *, struct timeval *);
static void timevalfix(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 void itimer_start(void);
static int itimer_init(void *, int, int); 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); return (0);
} }
static uint8_t nanowait[MAXCPU];
int int
kern_nanosleep(struct thread *td, struct timespec *rqt, struct timespec *rmt) kern_nanosleep(struct thread *td, struct timespec *rqt, struct timespec *rmt)
{ {
struct timespec ts;
return (kern_clock_nanosleep(td, CLOCK_REALTIME, TIMER_RELTIME, rqt,
rmt));
}
static uint8_t nanowait[MAXCPU];
int
kern_clock_nanosleep(struct thread *td, clockid_t clock_id, int flags,
const struct timespec *rqt, struct timespec *rmt)
{
struct timespec ts, now;
sbintime_t sbt, sbtt, prec, tmp; sbintime_t sbt, sbtt, prec, tmp;
time_t over; time_t over;
int error; int error;
bool is_abs_real;
if (rqt->tv_nsec < 0 || rqt->tv_nsec >= 1000000000) if (rqt->tv_nsec < 0 || rqt->tv_nsec >= 1000000000)
return (EINVAL); return (EINVAL);
if (rqt->tv_sec < 0 || (rqt->tv_sec == 0 && rqt->tv_nsec == 0)) if ((flags & ~TIMER_ABSTIME) != 0)
return (0); return (EINVAL);
ts = *rqt; switch (clock_id) {
if (ts.tv_sec > INT32_MAX / 2) { case CLOCK_REALTIME:
over = ts.tv_sec - INT32_MAX / 2; case CLOCK_REALTIME_PRECISE:
ts.tv_sec -= over; case CLOCK_REALTIME_FAST:
} else case CLOCK_SECOND:
over = 0; is_abs_real = (flags & TIMER_ABSTIME) != 0;
tmp = tstosbt(ts); break;
prec = tmp; case CLOCK_MONOTONIC:
prec >>= tc_precexp; case CLOCK_MONOTONIC_PRECISE:
if (TIMESEL(&sbt, tmp)) case CLOCK_MONOTONIC_FAST:
sbt += tc_tick_sbt; case CLOCK_UPTIME:
sbt += tmp; case CLOCK_UPTIME_PRECISE:
error = tsleep_sbt(&nanowait[curcpu], PWAIT | PCATCH, "nanslp", case CLOCK_UPTIME_FAST:
sbt, prec, C_ABSOLUTE); 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) { if (error != EWOULDBLOCK) {
TIMESEL(&sbtt, tmp);
if (sbtt >= sbt)
return (0);
if (error == ERESTART) if (error == ERESTART)
error = EINTR; error = EINTR;
TIMESEL(&sbtt, tmp); if ((flags & TIMER_ABSTIME) == 0 && rmt != NULL) {
if (rmt != NULL) {
ts = sbttots(sbt - sbtt); ts = sbttots(sbt - sbtt);
ts.tv_sec += over; ts.tv_sec += over;
if (ts.tv_sec < 0) if (ts.tv_sec < 0)
timespecclear(&ts); timespecclear(&ts);
*rmt = ts; *rmt = ts;
} }
if (sbtt >= sbt)
return (0);
return (error); return (error);
} }
return (0); return (0);
@ -536,22 +587,49 @@ struct nanosleep_args {
/* ARGSUSED */ /* ARGSUSED */
int int
sys_nanosleep(struct thread *td, struct nanosleep_args *uap) 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; struct timespec rmt, rqt;
int error; int error;
error = copyin(uap->rqtp, &rqt, sizeof(rqt)); error = copyin(ua_rqtp, &rqt, sizeof(rqt));
if (error) if (error)
return (error); return (error);
if (ua_rmtp != NULL && (flags & TIMER_ABSTIME) == 0 &&
if (uap->rmtp && !useracc(ua_rmtp, sizeof(rmt), VM_PROT_WRITE))
!useracc((caddr_t)uap->rmtp, sizeof(rmt), VM_PROT_WRITE)) return (EFAULT);
return (EFAULT); error = kern_clock_nanosleep(td, clock_id, flags, &rqt, &rmt);
error = kern_nanosleep(td, &rqt, &rmt); if (error == EINTR && ua_rmtp != NULL && (flags & TIMER_ABSTIME) == 0) {
if (error == EINTR && uap->rmtp) {
int error2; int error2;
error2 = copyout(&rmt, uap->rmtp, sizeof(rmt)); error2 = copyout(&rmt, ua_rmtp, sizeof(rmt));
if (error2) if (error2)
error = error2; error = error2;
} }

View File

@ -461,7 +461,9 @@
struct ffclock_estimate *cest); } struct ffclock_estimate *cest); }
243 AUE_NULL STD { int ffclock_getestimate( \ 243 AUE_NULL STD { int ffclock_getestimate( \
struct ffclock_estimate *cest); } 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 245 AUE_NULL UNIMPL nosys
246 AUE_NULL UNIMPL nosys 246 AUE_NULL UNIMPL nosys
247 AUE_NULL STD { int clock_getcpuclockid2(id_t id,\ 247 AUE_NULL STD { int clock_getcpuclockid2(id_t id,\

View File

@ -82,6 +82,8 @@ int kern_clock_getres(struct thread *td, clockid_t clock_id,
struct timespec *ts); struct timespec *ts);
int kern_clock_gettime(struct thread *td, clockid_t clock_id, int kern_clock_gettime(struct thread *td, clockid_t clock_id,
struct timespec *ats); 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, int kern_clock_settime(struct thread *td, clockid_t clock_id,
struct timespec *ats); struct timespec *ats);
int kern_close(struct thread *td, int fd); int kern_close(struct thread *td, int fd);