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:
parent
3b61da190e
commit
d6de25428d
@ -46,7 +46,11 @@ ATF_TC_BODY(clock_nanosleep_remain, tc)
|
||||
rqtp.tv_sec = 0; rqtp.tv_nsec = 0;
|
||||
rmtp.tv_sec = -1; rmtp.tv_nsec = -1;
|
||||
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);
|
||||
#endif
|
||||
|
||||
ATF_REQUIRE(clock_gettime(CLOCK_REALTIME, &rqtp) == 0);
|
||||
rmtp.tv_sec = -1; rmtp.tv_nsec = -1;
|
||||
|
@ -169,12 +169,12 @@ void tzset(void);
|
||||
int clock_getres(clockid_t, struct timespec *);
|
||||
int clock_gettime(clockid_t, struct timespec *);
|
||||
int clock_settime(clockid_t, const struct timespec *);
|
||||
/* XXX missing: clock_nanosleep() */
|
||||
int nanosleep(const struct timespec *, struct timespec *);
|
||||
#endif /* __POSIX_VISIBLE >= 199309 */
|
||||
|
||||
#if __POSIX_VISIBLE >= 200112
|
||||
int clock_getcpuclockid(pid_t, clockid_t *);
|
||||
int clock_nanosleep(clockid_t, int, const struct timespec *, struct timespec *);
|
||||
#endif
|
||||
|
||||
#if __POSIX_VISIBLE >= 199506
|
||||
|
@ -229,6 +229,7 @@ enum {
|
||||
INTERPOS_ppoll,
|
||||
INTERPOS_map_stacks_exec,
|
||||
INTERPOS_fdatasync,
|
||||
INTERPOS_clock_nanosleep,
|
||||
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_accept4(int, struct sockaddr *, __socklen_t *, int);
|
||||
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_connect(int, const struct sockaddr *, __socklen_t);
|
||||
int __sys_fcntl(int, int, ...);
|
||||
|
@ -56,6 +56,7 @@
|
||||
#define bind _bind
|
||||
#define __cap_get_fd ___cap_get_fd
|
||||
#define __cap_set_fd ___cap_set_fd
|
||||
#define clock_nanosleep _clock_nanosleep
|
||||
#define close _close
|
||||
#define connect _connect
|
||||
#define dup _dup
|
||||
|
@ -37,6 +37,7 @@
|
||||
#undef bind
|
||||
#undef __cap_get_fd
|
||||
#undef __cap_set_fd
|
||||
#undef clock_nanosleep
|
||||
#undef close
|
||||
#undef connect
|
||||
#undef dup
|
||||
|
@ -45,6 +45,7 @@ INTERPOSED = \
|
||||
accept \
|
||||
accept4 \
|
||||
aio_suspend \
|
||||
clock_nanosleep \
|
||||
close \
|
||||
connect \
|
||||
fcntl \
|
||||
@ -360,6 +361,7 @@ MLINKS+=chown.2 fchown.2 \
|
||||
chown.2 lchown.2
|
||||
MLINKS+=clock_gettime.2 clock_getres.2 \
|
||||
clock_gettime.2 clock_settime.2
|
||||
MLINKS+=nanosleep.2 clock_nanosleep.2
|
||||
MLINKS+=cpuset.2 cpuset_getid.2 \
|
||||
cpuset.2 cpuset_setid.2
|
||||
MLINKS+=cpuset_getaffinity.2 cpuset_setaffinity.2
|
||||
|
@ -399,6 +399,7 @@ FBSD_1.4 {
|
||||
};
|
||||
|
||||
FBSD_1.5 {
|
||||
clock_nanosleep;
|
||||
fdatasync;
|
||||
};
|
||||
|
||||
@ -511,6 +512,7 @@ FBSDprivate_1.0 {
|
||||
__sys_clock_getres;
|
||||
_clock_gettime;
|
||||
__sys_clock_gettime;
|
||||
__sys_clock_nanosleep;
|
||||
_clock_settime;
|
||||
__sys_clock_settime;
|
||||
_close;
|
||||
|
53
lib/libc/sys/clock_nanosleep.c
Normal file
53
lib/libc/sys/clock_nanosleep.c
Normal 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));
|
||||
}
|
@ -80,6 +80,7 @@ interpos_func_t __libc_interposing[INTERPOS_MAX] = {
|
||||
SLOT(ppoll, __sys_ppoll),
|
||||
SLOT(map_stacks_exec, __libc_map_stacks_exec),
|
||||
SLOT(fdatasync, __sys_fdatasync),
|
||||
SLOT(clock_nanosleep, __sys_clock_nanosleep),
|
||||
};
|
||||
#undef SLOT
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
.\" $OpenBSD: nanosleep.2,v 1.1 1997/04/20 20:56:20 tholo Exp $
|
||||
.\" $NetBSD: nanosleep.2,v 1.1 1997/04/17 18:12:02 jtc Exp $
|
||||
.\" $NetBSD: nanosleep.2,v 1.23 2016/11/14 10:40:59 wiz Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1986, 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
@ -31,51 +30,136 @@
|
||||
.\" @(#)sleep.3 8.1 (Berkeley) 6/4/93
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd April 17, 1997
|
||||
.Dd March 17, 2017
|
||||
.Dt NANOSLEEP 2
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm nanosleep
|
||||
.Nd suspend process execution for an interval measured in nanoseconds
|
||||
.Nd high resolution sleep
|
||||
.Sh LIBRARY
|
||||
.Lb libc
|
||||
.Sh SYNOPSIS
|
||||
.In time.h
|
||||
.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
|
||||
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
|
||||
.Fn nanosleep
|
||||
system call returns because the requested time has elapsed, the value
|
||||
returned will be zero.
|
||||
.Dv TIMER_ABSTIME
|
||||
flag is not set in the
|
||||
.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
|
||||
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
|
||||
system call returns due to the delivery of a signal, the value returned
|
||||
will be -1, and the global variable
|
||||
function behaves like
|
||||
.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
|
||||
will be set to indicate the interruption.
|
||||
If
|
||||
set to indicate the error.
|
||||
If a relative sleep is interrupted by a signal and
|
||||
.Fa rmtp
|
||||
is
|
||||
.No non- Ns Dv NULL ,
|
||||
.Pf non- Dv NULL ,
|
||||
the timespec structure it references is updated to contain the
|
||||
unslept amount (the request time minus the time actually slept).
|
||||
.Sh ERRORS
|
||||
The
|
||||
.Fn nanosleep
|
||||
system call fails if:
|
||||
These functions can fail with the following errors.
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er EFAULT
|
||||
Either
|
||||
@ -85,27 +169,32 @@ or
|
||||
points to memory that is not a valid part of the process
|
||||
address space.
|
||||
.It Bq Er EINTR
|
||||
The
|
||||
.Fn nanosleep
|
||||
system call
|
||||
was interrupted by the delivery of a signal.
|
||||
The function was interrupted by the delivery of a signal.
|
||||
.It Bq Er EINVAL
|
||||
The
|
||||
.Fa rqtp
|
||||
argument
|
||||
specified a nanosecond value less than zero
|
||||
argument specified a nanosecond value less than zero
|
||||
or greater than or equal to 1000 million.
|
||||
.It Bq Er ENOSYS
|
||||
.It Bq Er EINVAL
|
||||
The
|
||||
.Fn nanosleep
|
||||
system call
|
||||
is not supported by this implementation.
|
||||
.Fa flags
|
||||
argument contained an invalid flag.
|
||||
.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
|
||||
.Sh SEE ALSO
|
||||
.Xr sigsuspend 2 ,
|
||||
.Xr clock_gettime 2 ,
|
||||
.Xr sigaction 2 ,
|
||||
.Xr sleep 3
|
||||
.Sh STANDARDS
|
||||
The
|
||||
.Fn nanosleep
|
||||
system call conforms to
|
||||
.St -p1003.1b-93 .
|
||||
These functions conform to
|
||||
.St -p1003.1-2008 .
|
||||
|
@ -12,6 +12,7 @@ NETBSD_ATF_TESTS_C+= access_test
|
||||
NETBSD_ATF_TESTS_C+= bind_test
|
||||
NETBSD_ATF_TESTS_C+= chroot_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+= dup_test
|
||||
NETBSD_ATF_TESTS_C+= fsync_test
|
||||
|
@ -865,6 +865,8 @@ int __sys_sigwaitinfo(const sigset_t *set, siginfo_t *info);
|
||||
|
||||
/* #include <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 *);
|
||||
#endif
|
||||
|
||||
|
@ -259,6 +259,22 @@ __thr_msync(void *addr, size_t len, int flags)
|
||||
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
|
||||
__thr_nanosleep(const struct timespec *time_to_sleep,
|
||||
struct timespec *time_remaining)
|
||||
@ -668,6 +684,7 @@ __thr_interpose_libc(void)
|
||||
SLOT(ppoll);
|
||||
SLOT(map_stacks_exec);
|
||||
SLOT(fdatasync);
|
||||
SLOT(clock_nanosleep);
|
||||
#undef SLOT
|
||||
*(__libc_interposing_slot(
|
||||
INTERPOS__pthread_mutex_init_calloc_cb)) =
|
||||
|
@ -1,5 +1,5 @@
|
||||
.\" $FreeBSD$
|
||||
.Dd February 17, 2017
|
||||
.Dd March 18, 2017
|
||||
.Dt PTHREAD_TESTCANCEL 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -105,6 +105,7 @@ functions:
|
||||
.It Fn accept4
|
||||
.It Fn aio_suspend
|
||||
.It Fn connect
|
||||
.It Fn clock_nanosleep
|
||||
.It Fn close
|
||||
.It Fn creat
|
||||
.It Fn fcntl
|
||||
|
@ -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)
|
||||
@ -2225,29 +2227,49 @@ 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;
|
||||
}
|
||||
|
@ -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(\
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
static uint8_t nanowait[MAXCPU];
|
||||
|
||||
int
|
||||
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;
|
||||
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);
|
||||
@ -536,22 +587,49 @@ struct nanosleep_args {
|
||||
/* ARGSUSED */
|
||||
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;
|
||||
}
|
||||
|
@ -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,\
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user