From 3f66f7763430020e6517aac7842fd02d0a926def Mon Sep 17 00:00:00 2001
From: Aaron LI <aly@aaronly.me>
Date: Sun, 17 Jan 2021 16:08:41 +0800
Subject: [PATCH 8/8] Implement clock_nanosleep(2) system call

* Extend the nanosleep1() function in kern_time.c to support the
  clock_nanosleep(2) system call.  Add {kern,sys}_clock_nanosleep()
  functions and update kern_nanosleep() accordingly.

* Add clock_nanosleep() syscall to syscalls.master and regenerate
  syscall-related files.

* Update libc symbols with the new syscall.

* Add clock_nanosleep() warpper in libthread_xu.

* Update nanosleep.2 man page to describe clock_nanosleep().

* Update <time.h> and bump __DragonFly_version.

This work is loosely based on the FreeBSD implementation:
https://reviews.freebsd.org/rS315526

This clock_nanosleep(2) syscall passed all tests in the Open POSIX Test
Suite [0]:

conformance/interfaces/clock_nanosleep/1-1: execution: PASS
conformance/interfaces/clock_nanosleep/1-2: execution: PASS
conformance/interfaces/clock_nanosleep/1-3: execution: PASS
conformance/interfaces/clock_nanosleep/1-4: execution: PASS
conformance/interfaces/clock_nanosleep/1-5: execution: PASS
conformance/interfaces/clock_nanosleep/2-1: execution: PASS
conformance/interfaces/clock_nanosleep/2-2: execution: PASS
conformance/interfaces/clock_nanosleep/2-3: execution: PASS
conformance/interfaces/clock_nanosleep/3-1: execution: PASS
conformance/interfaces/clock_nanosleep/4-1: execution: PASS
conformance/interfaces/clock_nanosleep/5-1: execution: PASS
conformance/interfaces/clock_nanosleep/6-1: execution: PASS
conformance/interfaces/clock_nanosleep/9-1: execution: PASS
conformance/interfaces/clock_nanosleep/8-1: execution: PASS
conformance/interfaces/clock_nanosleep/10-1: execution: PASS
conformance/interfaces/clock_nanosleep/11-1: execution: PASS
conformance/interfaces/clock_nanosleep/13-1: execution: PASS
conformance/interfaces/clock_nanosleep/15-1: execution: PASS

[0] Open POSIX Test Suite: http://posixtest.sourceforge.net/
---
 include/time.h                         |   2 +-
 lib/libc/include/namespace.h           |   1 +
 lib/libc/include/un-namespace.h        |   1 +
 lib/libc/sys/Makefile.inc              |   5 +-
 lib/libc/sys/Symbol.map                |   6 +
 lib/libc/sys/nanosleep.2               | 185 +++++++++++++++++++++----
 lib/libpthread/pthread_testcancel.3    |   3 +-
 lib/libthread_xu/thread/thr_private.h  |   2 +
 lib/libthread_xu/thread/thr_syscalls.c |  20 +++
 sys/kern/init_sysent.c                 |   2 +-
 sys/kern/kern_time.c                   | 136 ++++++++++++++----
 sys/kern/syscalls.c                    |   2 +-
 sys/kern/syscalls.master               |   4 +-
 sys/sys/param.h                        |   3 +-
 sys/sys/syscall.h                      |   1 +
 sys/sys/syscall.mk                     |   1 +
 sys/sys/sysproto.h                     |   7 +
 sys/sys/sysunion.h                     |   1 +
 sys/sys/time.h                         |  10 +-
 19 files changed, 329 insertions(+), 63 deletions(-)

diff --git a/include/time.h b/include/time.h
index 761f65b5dfa..79d41050473 100644
--- a/include/time.h
+++ b/include/time.h
@@ -178,9 +178,9 @@ struct tm *localtime_r(const time_t * __restrict, struct tm * __restrict);
 
 #if __POSIX_VISIBLE >= 200112
 int clock_getcpuclockid(pid_t, clockid_t *);
+int clock_nanosleep(clockid_t, int, const struct timespec *, struct timespec *);
 #if 0 /* XXX missing */
 struct sigevent;
-int clock_nanosleep(clockid_t, int, const struct timespec *, struct timespec *);
 int timer_create(clockid_t, struct sigevent *__restrict, timer_t *__restrict);
 int timer_delete(timer_t);
 int timer_gettime(timer_t, struct itimerspec *);
diff --git a/lib/libc/include/namespace.h b/lib/libc/include/namespace.h
index 4deace27633..ec7d9483b4b 100644
--- a/lib/libc/include/namespace.h
+++ b/lib/libc/include/namespace.h
@@ -50,6 +50,7 @@
  */
 #define		accept				_accept
 #define		bind				_bind
+#define		clock_nanosleep			_clock_nanosleep
 #define		close				_close
 #define		connect				_connect
 #define		dup				_dup
diff --git a/lib/libc/include/un-namespace.h b/lib/libc/include/un-namespace.h
index 5e211a62b1b..22b92b1eedf 100644
--- a/lib/libc/include/un-namespace.h
+++ b/lib/libc/include/un-namespace.h
@@ -31,6 +31,7 @@
 
 #undef		accept
 #undef		bind
+#undef		clock_nanosleep
 #undef		close
 #undef		connect
 #undef		dup
diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc
index 1c418116c8b..536ced4b574 100644
--- a/lib/libc/sys/Makefile.inc
+++ b/lib/libc/sys/Makefile.inc
@@ -17,7 +17,7 @@ CMAPS+=	${.CURDIR}/sys/Symbol.map
 #
 .include "${.CURDIR}/../libc/${MACHINE_ARCH}/sys/Makefile.inc"
 
-SRCS+= fork.c
+SRCS+=	fork.c
 
 # Sources common to both syscall interfaces:
 SRCS+=	ftruncate.c lseek.c mmap.c truncate.c
@@ -25,7 +25,7 @@ SRCS+=	pread.c pwrite.c preadv.c pwritev.c
 SRCS+=	sched_getaffinity.c sched_getcpu.c sched_setaffinity.c
 
 # Add machine dependent asm sources:
-SRCS+=${MDASM}
+SRCS+=	${MDASM}
 
 # Look through the complete list of syscalls (MIASM) for names that are
 # not defined with machine dependent implementations (MDASM) and are
@@ -163,6 +163,7 @@ MLINKS+=msgctl.2 msgctl.3
 MLINKS+=msgget.2 msgget.3
 MLINKS+=msgrcv.2 msgrcv.3
 MLINKS+=msgsnd.2 msgsnd.3
+MLINKS+=nanosleep.2 clock_nanosleep.2
 MLINKS+=open.2 openat.2
 MLINKS+=pathconf.2 fpathconf.2 \
 	pathconf.2 lpathconf.2
diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map
index 756df1da64c..e9454ff10d5 100644
--- a/lib/libc/sys/Symbol.map
+++ b/lib/libc/sys/Symbol.map
@@ -331,6 +331,10 @@ DF504.0 {
     wait6;
 };
 
+DF510.0 {
+    clock_nanosleep;
+};
+
 DFprivate_1.0 {
     __fork;
 
@@ -370,6 +374,7 @@ DFprivate_1.0 {
     __sys_chroot_kernel;
     __sys_clock_getres;
     __sys_clock_gettime;
+    __sys_clock_nanosleep;
     __sys_clock_settime;
     __sys_close;
     __sys_closefrom;
@@ -673,6 +678,7 @@ DFprivate_1.0 {
     _chroot_kernel;
     _clock_getres;
     _clock_gettime;
+    _clock_nanosleep;
     _clock_settime;
     _close;
     _closefrom;
diff --git a/lib/libc/sys/nanosleep.2 b/lib/libc/sys/nanosleep.2
index e0320e6c368..c1d42965bf4 100644
--- a/lib/libc/sys/nanosleep.2
+++ b/lib/libc/sys/nanosleep.2
@@ -1,5 +1,4 @@
 .\" $FreeBSD: src/lib/libc/sys/nanosleep.2,v 1.8.2.5 2002/12/20 18:39:35 ceri Exp $
-.\" $DragonFly: src/lib/libc/sys/nanosleep.2,v 1.2 2003/06/17 04:26:47 dillon Exp $
 .\"	$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 $
 .\"
@@ -32,46 +31,163 @@
 .\"
 .\"     @(#)sleep.3	8.1 (Berkeley) 6/4/93
 .\"
-.Dd April 17, 1997
+.Dd January 17, 2021
 .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 nanosleep
+.Fa "const struct timespec *rqtp"
+.Fa "struct timespec *rmtp"
+.Fc
+.Ft int
+.Fo clock_nanosleep
+.Fa "clockid_t clock_id"
+.Fa "int flags"
+.Fa "const struct timespec *rqtp"
+.Fa "struct timespec *rmtp"
+.Fc
 .Sh DESCRIPTION
-.Fn Nanosleep
-causes the process to sleep for the specified time.  An unmasked signal will
-cause it to terminate the sleep early, regardless of the
+Both
+.Fn nanosleep
+and
+.Fn clock_nanosleep
+allow to suspend the calling thread for an interval
+measured in nanoseconds.
+Compared to
+.Fn nanosleep ,
+.Fn clock_nanosleep
+further allows the caller to select the clock against which
+the suspension interval is to be measured,
+and allows the suspension interval to be specified as either a relative
+or an absolute value.
+.Pp
+If the
+.Fa flags
+argument is 0 (i.e., the
+.Dv TIMER_ABSTIME
+flag is not set),
+the value specified in the
+.Fa rqtp
+argument is interpreted as an interval relative to the current time
+measured in the clock specified by the
+.Fa clock_id
+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.
+.Pp
+If the
+.Fa flags
+argument is
+.Dv TIMER_ABSTIME ,
+the value specified in the
+.Fa rqtp
+argument is interpreted as an absolute time measured by the
+.Fa clock_id
+clock.
+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.
-.Sh RETURN VALUES
-If the
+The
+.Fa rqtp
+and
+.Fa rmtp
+arguments can point to the same object.
+.Pp
+The following
+.Fa clock_id
+values (see
+.Xr clock_gettime 2
+for their meanings) 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
-function returns because the requested time has elapsed, the value
-returned will be zero.
+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.
 .Pp
-If the
+The use of these functions has no effect on the action or blockage of any signal.
+.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
-function returns due to the delivery of a signal, the value returned
-will be -1, and the global variable
+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
 .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
-call fails if:
+These functions can fail with the following errors:
 .Bl -tag -width Er
 .It Bq Er EFAULT
 Either
@@ -81,21 +197,38 @@ or
 points to memory that is not a valid part of the process
 address space.
 .It Bq Er EINTR
-.Fn nanosleep
-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
-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
-.Fn nanosleep
-is not supported by this implementation.
+.It Bq Er EINVAL
+The
+.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
 function conforms to
 .St -p1003.1b-93 .
+The
+.Fn clock_nanosleep
+function conforms to
+.St -p1003.1-2008 .
diff --git a/lib/libpthread/pthread_testcancel.3 b/lib/libpthread/pthread_testcancel.3
index 8cb64093211..7f0771e84eb 100644
--- a/lib/libpthread/pthread_testcancel.3
+++ b/lib/libpthread/pthread_testcancel.3
@@ -1,5 +1,5 @@
 .\" $FreeBSD: src/share/man/man3/pthread_testcancel.3,v 1.15 2007/10/22 10:08:01 ru Exp $
-.Dd July 10, 2009
+.Dd January 17, 2021
 .Dt PTHREAD_TESTCANCEL 3
 .Os
 .Sh NAME
@@ -99,6 +99,7 @@ type will be in effect.
 .Ss Cancellation Points
 Cancellation points will occur when a thread is executing the following
 functions:
+.Fn clock_nanosleep ,
 .Fn close ,
 .Fn creat ,
 .Fn fcntl ,
diff --git a/lib/libthread_xu/thread/thr_private.h b/lib/libthread_xu/thread/thr_private.h
index 70520829a77..ca4f4a76849 100644
--- a/lib/libthread_xu/thread/thr_private.h
+++ b/lib/libthread_xu/thread/thr_private.h
@@ -758,6 +758,8 @@ int     __sys_sigaltstack(const stack_t *, stack_t *);
 /* #include <time.h> */
 #ifdef	_TIME_H_
 int	__sys_nanosleep(const struct timespec *, struct timespec *);
+int	__sys_clock_nanosleep(clockid_t, int, const struct timespec *,
+		struct timespec *);
 #endif
 
 /* #include <unistd.h> */
diff --git a/lib/libthread_xu/thread/thr_syscalls.c b/lib/libthread_xu/thread/thr_syscalls.c
index ca0fce309e6..5e353a3ebc2 100644
--- a/lib/libthread_xu/thread/thr_syscalls.c
+++ b/lib/libthread_xu/thread/thr_syscalls.c
@@ -129,6 +129,8 @@ int	__fcntl(int, int,...);
 int	__fsync(int);
 int	__msync(void *, size_t, int);
 int	__nanosleep(const struct timespec *, struct timespec *);
+int	__clock_nanosleep(clock_t, int, const struct timespec *,
+		struct timespec *);
 int	__open(const char *, int,...);
 int	__openat(int fd, const char *, int,...);
 int	__poll(struct pollfd *, unsigned int, int);
@@ -325,6 +327,24 @@ __nanosleep(const struct timespec *time_to_sleep,
 
 __strong_reference(__nanosleep, nanosleep);
 
+int
+__clock_nanosleep(clock_t clock_id, int flags,
+    const struct timespec *time_to_sleep, struct timespec *time_remaining)
+{
+	pthread_t curthread = tls_get_curthread();
+	int		oldcancel;
+	int		ret;
+
+	oldcancel = _thr_cancel_enter(curthread);
+	ret = __sys_clock_nanosleep(clock_id, flags, time_to_sleep,
+			time_remaining);
+	_thr_cancel_leave(curthread, oldcancel);
+
+	return (ret);
+}
+
+__strong_reference(__clock_nanosleep, clock_nanosleep);
+
 int
 __open(const char *path, int flags,...)
 {
diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c
index b9124bf89d8..1659fb8145a 100644
--- a/sys/kern/init_sysent.c
+++ b/sys/kern/init_sysent.c
@@ -255,7 +255,7 @@ struct sysent sysent[] = {
 	{ 0, (sy_call_t *)sys_nosys },			/* 238 = timer_gettime */
 	{ 0, (sy_call_t *)sys_nosys },			/* 239 = timer_getoverrun */
 	{ AS(nanosleep_args), (sy_call_t *)sys_nanosleep },	/* 240 = nanosleep */
-	{ 0, (sy_call_t *)sys_nosys },			/* 241 = nosys */
+	{ AS(clock_nanosleep_args), (sy_call_t *)sys_clock_nanosleep },	/* 241 = clock_nanosleep */
 	{ 0, (sy_call_t *)sys_nosys },			/* 242 = nosys */
 	{ 0, (sy_call_t *)sys_nosys },			/* 243 = nosys */
 	{ 0, (sy_call_t *)sys_nosys },			/* 244 = nosys */
diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c
index 042384bfffc..116a863a46f 100644
--- a/sys/kern/kern_time.c
+++ b/sys/kern/kern_time.c
@@ -117,7 +117,7 @@ settime(struct timeval *tv)
 	timevalsub(&delta, &tv1);
 
 	/*
-	 * If the system is secure, we do not allow the time to be 
+	 * If the system is secure, we do not allow the time to be
 	 * set to a value earlier than 1 second less than the highest
 	 * time we have yet seen. The worst a miscreant can do in
 	 * this circumstance is "freeze" time. He couldn't go
@@ -328,7 +328,7 @@ kern_clock_getres(clockid_t clock_id, struct timespec *ts)
 {
 	ts->tv_sec = 0;
 
-	switch(clock_id) {
+	switch (clock_id) {
 	case CLOCK_REALTIME:
 	case CLOCK_REALTIME_FAST:
 	case CLOCK_REALTIME_PRECISE:
@@ -431,19 +431,19 @@ sys_getcpuclockid(struct sysmsg *sysmsg, const struct getcpuclockid_args *uap)
 }
 
 /*
- * nanosleep1()
+ * clock_nanosleep1()
  *
- *	This is a general helper function for nanosleep() (aka sleep() aka
- *	usleep()).
+ *	This is a general helper function for clock_nanosleep() and
+ *	nanosleep() (aka sleep(), aka usleep()).
  *
- *	If there is less then one tick's worth of time left and
+ *	If there is less than one tick's worth of time left and
  *	we haven't done a yield, or the remaining microseconds is
  *	ridiculously low, do a yield.  This avoids having
  *	to deal with systimer overheads when the system is under
  *	heavy loads.  If we have done a yield already then use
  *	a systimer and an uninterruptable thread wait.
  *
- *	If there is more then a tick's worth of time left,
+ *	If there is more than a tick's worth of time left,
  *	calculate the baseline ticks and use an interruptable
  *	tsleep, then handle the fine-grained delay on the next
  *	loop.  This usually results in two sleeps occuring, a long one
@@ -459,30 +459,70 @@ ns1_systimer(systimer_t info, int in_ipi __unused,
 }
 
 int
-nanosleep1(struct timespec *rqt, struct timespec *rmt)
+clock_nanosleep1(clockid_t clock_id, int flags,
+    struct timespec *rqt, struct timespec *rmt)
 {
 	static int nanowait;
-	struct timespec ts, ts2, ts3;
+	struct timespec ts_cur, ts_tgt, ts_int;
 	struct timeval tv;
-	int error;
+	bool is_abs;
+	int error, error2;
 
+	if ((flags & ~(TIMER_RELTIME | TIMER_ABSTIME)) != 0)
+		return (EINVAL);
 	if (rqt->tv_sec < 0 || rqt->tv_nsec < 0 || rqt->tv_nsec >= 1000000000)
 		return (EINVAL);
 	if (rqt->tv_sec == 0 && rqt->tv_nsec == 0)
 		return (0);
 
-	nanouptime(&ts);
-	timespecadd(&ts, rqt, &ts);	/* ts = target timestamp compare */
-	TIMESPEC_TO_TIMEVAL(&tv, rqt);	/* tv = sleep interval */
+	switch (clock_id) {
+	case CLOCK_REALTIME:
+	case CLOCK_REALTIME_FAST:
+	case CLOCK_REALTIME_PRECISE:
+	case CLOCK_SECOND:
+	case CLOCK_MONOTONIC:
+	case CLOCK_MONOTONIC_FAST:
+	case CLOCK_MONOTONIC_PRECISE:
+	case CLOCK_UPTIME:
+	case CLOCK_UPTIME_FAST:
+	case CLOCK_UPTIME_PRECISE:
+		is_abs = (flags & TIMER_ABSTIME) != 0;
+		break;
+	case CLOCK_VIRTUAL:
+	case CLOCK_PROF:
+	case CLOCK_PROCESS_CPUTIME_ID:
+		return (ENOTSUP);
+	case CLOCK_THREAD_CPUTIME_ID:
+	default:
+		return (EINVAL);
+	}
+
+	error = kern_clock_gettime(clock_id, &ts_cur);
+	if (error)
+		return (error);
+
+	if (is_abs) {
+		if (timespeccmp(&ts_cur, rqt, >=))
+			return (0);
+
+		ts_tgt = *rqt; /* target timestamp */
+		timespecsub(&ts_tgt, &ts_cur, &ts_int); /* sleep interval */
+	} else {
+		ts_int = *rqt; /* sleep interval */
+		timespecadd(&ts_cur, &ts_int, &ts_tgt); /* target timestamp */
+	}
 
 	for (;;) {
 		int ticks;
 		struct systimer info;
+		thread_t td;
 
-		ticks = tv.tv_usec / ustick;	/* approximate */
+		timespecsub(&ts_tgt, &ts_cur, &ts_int);
+		TIMESPEC_TO_TIMEVAL(&tv, &ts_int);
+		ticks = tv.tv_usec / ustick; /* approximate */
 
 		if (tv.tv_sec == 0 && ticks == 0) {
-			thread_t td = curthread;
+			td = curthread;
 			if (tv.tv_usec > 0 && tv.tv_usec < nanosleep_min_us)
 				tv.tv_usec = nanosleep_min_us;
 			if (tv.tv_usec < nanosleep_hard_us) {
@@ -504,25 +544,71 @@ nanosleep1(struct timespec *rqt, struct timespec *rmt)
 			ticks = tvtohz_low(&tv); /* also handles overflow */
 			error = tsleep(&nanowait, PCATCH, "nanslp", ticks);
 		}
-		nanouptime(&ts2);
+
+		error2 = kern_clock_gettime(clock_id, &ts_cur);
+		if (error2)
+			return (error2);
+
 		if (error && error != EWOULDBLOCK) {
 			if (error == ERESTART)
 				error = EINTR;
-			if (rmt != NULL) {
-				timespecsub(&ts, &ts2, &ts);
-				if (ts.tv_sec < 0)
-					timespecclear(&ts);
-				*rmt = ts;
+			if (rmt != NULL && !is_abs) {
+				timespecsub(&ts_tgt, &ts_cur, &ts_int);
+				if (ts_int.tv_sec < 0)
+					timespecclear(&ts_int);
+				*rmt = ts_int;
 			}
 			return (error);
 		}
-		if (timespeccmp(&ts2, &ts, >=))
+		if (timespeccmp(&ts_cur, &ts_tgt, >=))
 			return (0);
-		timespecsub(&ts, &ts2, &ts3);
-		TIMESPEC_TO_TIMEVAL(&tv, &ts3);
 	}
 }
 
+int
+nanosleep1(struct timespec *rqt, struct timespec *rmt)
+{
+	return clock_nanosleep1(CLOCK_REALTIME, TIMER_RELTIME, rqt, rmt);
+}
+
+/*
+ * MPSAFE
+ */
+int
+sys_clock_nanosleep(struct sysmsg *sysmsg,
+    const struct clock_nanosleep_args *uap)
+{
+	int error;
+	bool is_abs;
+	struct timespec rqt;
+	struct timespec rmt;
+
+	is_abs = (uap->flags & TIMER_ABSTIME) != 0;
+
+	error = copyin(uap->rqtp, &rqt, sizeof(rqt));
+	if (error) {
+		sysmsg->sysmsg_result = error;
+		return (0);
+	}
+
+	bzero(&rmt, sizeof(rmt));
+	error = clock_nanosleep1(uap->clock_id, uap->flags, &rqt, &rmt);
+
+	/*
+	 * copyout the residual if nanosleep was interrupted.
+	 */
+	if (error == EINTR && uap->rmtp != NULL && !is_abs) {
+		int error2;
+
+		error2 = copyout(&rmt, uap->rmtp, sizeof(rmt));
+		if (error2)
+			error = error2;
+	}
+
+	sysmsg->sysmsg_result = error;
+	return (0);
+}
+
 /*
  * MPSAFE
  */
@@ -543,7 +629,7 @@ sys_nanosleep(struct sysmsg *sysmsg, const struct nanosleep_args *uap)
 	/*
 	 * copyout the residual if nanosleep was interrupted.
 	 */
-	if (error == EINTR && uap->rmtp) {
+	if (error == EINTR && uap->rmtp != NULL) {
 		int error2;
 
 		error2 = copyout(&rmt, uap->rmtp, sizeof(rmt));
diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c
index f0176b51076..e171d596041 100644
--- a/sys/kern/syscalls.c
+++ b/sys/kern/syscalls.c
@@ -247,7 +247,7 @@ const char *syscallnames[] = {
 	"#238",			/* 238 = timer_gettime */
 	"#239",			/* 239 = timer_getoverrun */
 	"nanosleep",			/* 240 = nanosleep */
-	"#241",			/* 241 = nosys */
+	"clock_nanosleep",			/* 241 = clock_nanosleep */
 	"#242",			/* 242 = nosys */
 	"#243",			/* 243 = nosys */
 	"#244",			/* 244 = nosys */
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index eb3bfdaf345..30f2de24b3d 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -345,7 +345,9 @@
 239	UNIMPL	timer_getoverrun
 240	STD	{ int nanosleep(const struct timespec *rqtp, \
 			    struct timespec *rmtp); }
-241	UNIMPL	nosys
+241	STD	{ int clock_nanosleep(clockid_t clock_id, int flags, \
+			    const struct timespec *rqtp, \
+			    struct timespec *rmtp); }
 242	UNIMPL	nosys
 243	UNIMPL	nosys
 244	UNIMPL	nosys
diff --git a/sys/sys/param.h b/sys/sys/param.h
index a2ca5648cbf..4d1ff905acf 100644
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -223,9 +223,10 @@
  * 500905 - add IPPROTO_IP/IP_SENDSRCADDR and IP_TOS control message.
  * 500906 - add struct ip_mreqn for IPPROTO_IP/IP_MULTICAST_IF,
  *          IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP.
+ * 500907 - add clock_nanosleep()
  */
 #undef __DragonFly_version
-#define __DragonFly_version 500906	/* propagated to newvers */
+#define __DragonFly_version 500907	/* propagated to newvers */
 
 #include <sys/_null.h>
 
diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h
index e6136779d23..c6226679703 100644
--- a/sys/sys/syscall.h
+++ b/sys/sys/syscall.h
@@ -203,6 +203,7 @@
 #define	SYS_clock_settime	233
 #define	SYS_clock_getres	234
 #define	SYS_nanosleep	240
+#define	SYS_clock_nanosleep	241
 #define	SYS_minherit	250
 #define	SYS_rfork	251
 #define	SYS_openbsd_poll	252
diff --git a/sys/sys/syscall.mk b/sys/sys/syscall.mk
index c85b1c531af..10b1385da26 100644
--- a/sys/sys/syscall.mk
+++ b/sys/sys/syscall.mk
@@ -149,6 +149,7 @@ MIASM =  \
 	clock_settime.o \
 	clock_getres.o \
 	nanosleep.o \
+	clock_nanosleep.o \
 	minherit.o \
 	rfork.o \
 	openbsd_poll.o \
diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h
index cfe351a8453..536028e2b88 100644
--- a/sys/sys/sysproto.h
+++ b/sys/sys/sysproto.h
@@ -651,6 +651,12 @@ struct	nanosleep_args {
 	const struct timespec *	rqtp;	char rqtp_[PAD_(const struct timespec *)];
 	struct timespec *	rmtp;	char rmtp_[PAD_(struct timespec *)];
 };
+struct	clock_nanosleep_args {
+	clockid_t	clock_id;	char clock_id_[PAD_(clockid_t)];
+	int	flags;	char flags_[PAD_(int)];
+	const struct timespec *	rqtp;	char rqtp_[PAD_(const struct timespec *)];
+	struct timespec *	rmtp;	char rmtp_[PAD_(struct timespec *)];
+};
 struct	minherit_args {
 	void *	addr;	char addr_[PAD_(void *)];
 	size_t	len;	char len_[PAD_(size_t)];
@@ -1586,6 +1592,7 @@ int	sys_clock_gettime (struct sysmsg *sysmsg, const struct clock_gettime_args *)
 int	sys_clock_settime (struct sysmsg *sysmsg, const struct clock_settime_args *);
 int	sys_clock_getres (struct sysmsg *sysmsg, const struct clock_getres_args *);
 int	sys_nanosleep (struct sysmsg *sysmsg, const struct nanosleep_args *);
+int	sys_clock_nanosleep (struct sysmsg *sysmsg, const struct clock_nanosleep_args *);
 int	sys_minherit (struct sysmsg *sysmsg, const struct minherit_args *);
 int	sys_rfork (struct sysmsg *sysmsg, const struct rfork_args *);
 int	sys_openbsd_poll (struct sysmsg *sysmsg, const struct openbsd_poll_args *);
diff --git a/sys/sys/sysunion.h b/sys/sys/sysunion.h
index d489a8d0d41..592de73f496 100644
--- a/sys/sys/sysunion.h
+++ b/sys/sys/sysunion.h
@@ -151,6 +151,7 @@ union sysunion {
 	struct	clock_settime_args clock_settime;
 	struct	clock_getres_args clock_getres;
 	struct	nanosleep_args nanosleep;
+	struct	clock_nanosleep_args clock_nanosleep;
 	struct	minherit_args minherit;
 	struct	rfork_args rfork;
 	struct	openbsd_poll_args openbsd_poll;
diff --git a/sys/sys/time.h b/sys/sys/time.h
index 807787a08b2..1094498a02d 100644
--- a/sys/sys/time.h
+++ b/sys/sys/time.h
@@ -220,12 +220,14 @@ int	tstohz_high(struct timespec *);
 int	tstohz_low(struct timespec *);
 int	tsc_test_target(int64_t target);
 void	tsc_delay(int ns);
+int	clock_nanosleep1(clockid_t clock_id, int flags,
+		struct timespec *rqt, struct timespec *rmt);
 int	nanosleep1(struct timespec *rqt, struct timespec *rmt);
 
-void timespec2fattime(const struct timespec *tsp, int utc, u_int16_t *ddp,
-    u_int16_t *dtp, u_int8_t *dhp);
-void fattime2timespec(unsigned dd, unsigned dt, unsigned dh, int utc,
-    struct timespec *tsp);
+void	timespec2fattime(const struct timespec *tsp, int utc, u_int16_t *ddp,
+		u_int16_t *dtp, u_int8_t *dhp);
+void	fattime2timespec(unsigned dd, unsigned dt, unsigned dh, int utc,
+		struct timespec *tsp);
 
 tsc_uclock_t tsc_get_target(int ns);
 
-- 
2.30.0

