summary refs log tree commit diff
path: root/time
diff options
context:
space:
mode:
Diffstat (limited to 'time')
-rw-r--r--time/Makefile8
-rw-r--r--time/Versions13
-rw-r--r--time/clock_getcpuclockid.c47
-rw-r--r--time/clock_getres.c39
-rw-r--r--time/clock_gettime.c40
-rw-r--r--time/clock_nanosleep.c46
-rw-r--r--time/clock_settime.c40
-rw-r--r--time/tst-clock.c121
-rw-r--r--time/tst-clock2.c43
-rw-r--r--time/tst-clock_nanosleep.c57
-rw-r--r--time/tst-cpuclock1.c320
11 files changed, 772 insertions, 2 deletions
diff --git a/time/Makefile b/time/Makefile
index a428f55245..85a62c0376 100644
--- a/time/Makefile
+++ b/time/Makefile
@@ -36,14 +36,18 @@ routines := offtime asctime clock ctime ctime_r difftime \
 	    stime dysize timegm ftime			 \
 	    getdate strptime strptime_l			 \
 	    strftime wcsftime strftime_l wcsftime_l	 \
-	    timespec_get
+	    timespec_get 	 			 \
+	    clock_getcpuclockid clock_getres 		 \
+	    clock_gettime clock_settime clock_nanosleep
+
 aux :=	    era alt_digit lc-time-cleanup
 
 tests	:= test_time clocktest tst-posixtz tst-strptime tst_wcsftime \
 	   tst-getdate tst-mktime tst-mktime2 tst-ftime_l tst-strftime \
 	   tst-mktime3 tst-strptime2 bug-asctime bug-asctime_r bug-mktime1 \
 	   tst-strptime3 bug-getdate1 tst-strptime-whitespace tst-ftime \
-	   tst-tzname tst-y2039 bug-mktime4 tst-strftime2 tst-strftime3
+	   tst-tzname tst-y2039 bug-mktime4 tst-strftime2 tst-strftime3 \
+	   tst-clock tst-clock2 tst-clock_nanosleep tst-cpuclock1
 
 include ../Rules
 
diff --git a/time/Versions b/time/Versions
index fd838181e4..8788e192ce 100644
--- a/time/Versions
+++ b/time/Versions
@@ -49,6 +49,10 @@ libc {
   GLIBC_2.2 {
     # w*
     wcsftime;
+
+    # c*; actually in librt in version 2.2, moved to libc in 2.17
+    clock_getres; clock_gettime; clock_settime; clock_getcpuclockid;
+    clock_nanosleep;
   }
   GLIBC_2.3 {
     # these internal names are used by libstdc++
@@ -65,4 +69,13 @@ libc {
   GLIBC_2.16 {
     timespec_get;
   }
+  GLIBC_2.17 {
+    # c*
+    clock_getres; clock_gettime; clock_settime; clock_getcpuclockid;
+    clock_nanosleep;
+  }
+  GLIBC_PRIVATE {
+    # same as clock_gettime; used in other libraries
+    __clock_gettime;
+  }
 }
diff --git a/time/clock_getcpuclockid.c b/time/clock_getcpuclockid.c
new file mode 100644
index 0000000000..8d205abfa9
--- /dev/null
+++ b/time/clock_getcpuclockid.c
@@ -0,0 +1,47 @@
+/* Get a clockid_t for the process CPU clock of a given process.  Generic.
+   Copyright (C) 2000-2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <time.h>
+#include <unistd.h>
+#include <shlib-compat.h>
+
+int
+__clock_getcpuclockid (pid_t pid, clockid_t *clock_id)
+{
+  /* We don't allow any process ID but our own.  */
+  if (pid != 0 && pid != getpid ())
+    return EPERM;
+
+#ifdef CLOCK_PROCESS_CPUTIME_ID
+  /* Store the number.  */
+  *clock_id = CLOCK_PROCESS_CPUTIME_ID;
+
+  return 0;
+#else
+  /* We don't have a timer for that.  */
+  return ENOENT;
+#endif
+}
+versioned_symbol (libc, __clock_getcpuclockid, clock_getcpuclockid, GLIBC_2_17);
+/* clock_getcpuclockid moved to libc in version 2.17;
+   old binaries may expect the symbol version it had in librt.  */
+#if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_17)
+strong_alias (__clock_getcpuclockid, __clock_getcpuclockid_2);
+compat_symbol (libc, __clock_getcpuclockid_2, clock_getcpuclockid, GLIBC_2_2);
+#endif
diff --git a/time/clock_getres.c b/time/clock_getres.c
new file mode 100644
index 0000000000..412f80fbec
--- /dev/null
+++ b/time/clock_getres.c
@@ -0,0 +1,39 @@
+/* Get the resolution of a clock.  Stub version.
+   Copyright (C) 1999-2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <time.h>
+#include <shlib-compat.h>
+
+/* Get resolution of clock.  */
+int
+__clock_getres (clockid_t clock_id, struct timespec *res)
+{
+  __set_errno (ENOSYS);
+  return -1;
+}
+
+versioned_symbol (libc, __clock_getres, clock_getres, GLIBC_2_17);
+/* clock_getres moved to libc in version 2.17;
+   old binaries may expect the symbol version it had in librt.  */
+#if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_17)
+strong_alias (__clock_getres, __clock_getres_2);
+compat_symbol (libc, __clock_getres_2, clock_getres, GLIBC_2_2);
+#endif
+
+stub_warning (clock_getres)
diff --git a/time/clock_gettime.c b/time/clock_gettime.c
new file mode 100644
index 0000000000..92c6081dcb
--- /dev/null
+++ b/time/clock_gettime.c
@@ -0,0 +1,40 @@
+/* Get the current value of a clock.  Stub version.
+   Copyright (C) 1999-2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <time.h>
+#include <shlib-compat.h>
+
+/* Get current value of CLOCK and store it in TP.  */
+int
+__clock_gettime (clockid_t clock_id, struct timespec *tp)
+{
+  __set_errno (ENOSYS);
+  return -1;
+}
+libc_hidden_def (__clock_gettime)
+
+versioned_symbol (libc, __clock_gettime, clock_gettime, GLIBC_2_17);
+/* clock_gettime moved to libc in version 2.17;
+   old binaries may expect the symbol version it had in librt.  */
+#if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_17)
+strong_alias (__clock_gettime, __clock_gettime_2);
+compat_symbol (libc, __clock_gettime_2, clock_gettime, GLIBC_2_2);
+#endif
+
+stub_warning (clock_gettime)
diff --git a/time/clock_nanosleep.c b/time/clock_nanosleep.c
new file mode 100644
index 0000000000..c53c820880
--- /dev/null
+++ b/time/clock_nanosleep.c
@@ -0,0 +1,46 @@
+/* High-resolution sleep with the specified clock.  Stub version.
+   Copyright (C) 2000-2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <time.h>
+#include <shlib-compat.h>
+
+int
+__clock_nanosleep (clockid_t clock_id, int flags, const struct timespec *req,
+		   struct timespec *rem)
+{
+  if (__builtin_expect (req->tv_nsec, 0) < 0
+      || __builtin_expect (req->tv_nsec, 0) >= 1000000000)
+    return EINVAL;
+
+  if (flags != TIMER_ABSTIME && flags != 0)
+    return EINVAL;
+
+  /* Not implemented.  */
+  return ENOSYS;
+}
+
+versioned_symbol (libc, __clock_nanosleep, clock_nanosleep, GLIBC_2_17);
+/* clock_nanosleep moved to libc in version 2.17;
+   old binaries may expect the symbol version it had in librt.  */
+#if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_17)
+strong_alias (__clock_nanosleep, __clock_nanosleep_2);
+compat_symbol (libc, __clock_nanosleep_2, clock_nanosleep, GLIBC_2_2);
+#endif
+
+stub_warning (clock_nanosleep)
diff --git a/time/clock_settime.c b/time/clock_settime.c
new file mode 100644
index 0000000000..dd86a1c189
--- /dev/null
+++ b/time/clock_settime.c
@@ -0,0 +1,40 @@
+/* Set a clock to a given value.  Stub version.
+   Copyright (C) 1999-2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <time.h>
+#include <shlib-compat.h>
+
+/* Set CLOCK to value TP.  */
+int
+__clock_settime (clockid_t clock_id, const struct timespec *tp)
+{
+  __set_errno (ENOSYS);
+  return -1;
+}
+libc_hidden_def (__clock_settime)
+
+versioned_symbol (libc, __clock_settime, clock_settime, GLIBC_2_17);
+/* clock_settime moved to libc in version 2.17;
+   old binaries may expect the symbol version it had in librt.  */
+#if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_17)
+strong_alias (__clock_settime, __clock_settime_2);
+compat_symbol (libc, __clock_settime_2, clock_settime, GLIBC_2_2);
+#endif
+
+stub_warning (clock_settime)
diff --git a/time/tst-clock.c b/time/tst-clock.c
new file mode 100644
index 0000000000..2e19bb1a43
--- /dev/null
+++ b/time/tst-clock.c
@@ -0,0 +1,121 @@
+/* Test program for POSIX clock_* functions.
+   Copyright (C) 2000-2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 2000.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <stdint.h>
+
+
+/* We want to see output immediately.  */
+#define STDOUT_UNBUFFERED
+
+static int
+clock_test (clockid_t cl)
+{
+  struct timespec old_ts;
+  struct timespec ts;
+  struct timespec waitit;
+  int result = 0;
+  int i;
+
+  memset (&ts, '\0', sizeof ts);
+
+  waitit.tv_sec = 0;
+  waitit.tv_nsec = 500000000;
+
+  /* Get and print resolution of the clock.  */
+  if (clock_getres (cl, &ts) == 0)
+    {
+      if (ts.tv_nsec < 0 || ts.tv_nsec >= 1000000000)
+	{
+	  printf ("clock %d: nanosecond value of resolution wrong\n", cl);
+	  result = 1;
+	}
+      else
+	printf ("clock %d: resolution = %jd.%09jd secs\n",
+		cl, (intmax_t) ts.tv_sec, (intmax_t) ts.tv_nsec);
+    }
+  else
+    {
+      printf ("clock %d: cannot get resolution\n", cl);
+      result = 1;
+    }
+
+  memset (&ts, '\0', sizeof ts);
+  memset (&old_ts, '\0', sizeof old_ts);
+
+  /* Next get the current time value a few times.  */
+  for (i = 0; i < 10; ++i)
+    {
+      if (clock_gettime (cl, &ts) == 0)
+	{
+	  if (ts.tv_nsec < 0 || ts.tv_nsec >= 1000000000)
+	    {
+	      printf ("clock %d: nanosecond value of time wrong (try %d)\n",
+		      cl, i);
+	      result = 1;
+	    }
+	  else
+	    {
+	      printf ("clock %d: time = %jd.%09jd secs\n",
+		      cl, (intmax_t) ts.tv_sec, (intmax_t) ts.tv_nsec);
+
+	      if (memcmp (&ts, &old_ts, sizeof ts) == 0)
+		{
+		  printf ("clock %d: time hasn't changed (try %d)\n", cl, i);
+		  result = 1;
+
+		  old_ts = ts;
+		}
+	    }
+	}
+      else
+	{
+	  printf ("clock %d: cannot get time (try %d)\n", cl, i);
+	  result = 1;
+	}
+
+      /* Wait a bit before the next iteration.  */
+      nanosleep (&waitit, NULL);
+    }
+
+  return result;
+}
+
+static int
+do_test (void)
+{
+  clockid_t cl;
+  int result;
+
+  result = clock_test (CLOCK_REALTIME);
+
+  if (clock_getcpuclockid (0, &cl) == 0)
+    /* XXX It's not yet a bug when this fails.  */
+    clock_test (cl);
+  else
+	  printf("CPU clock unavailble, skipping test\n");
+
+  return result;
+}
+#define TEST_FUNCTION do_test ()
+
+
+#include "../test-skeleton.c"
diff --git a/time/tst-clock2.c b/time/tst-clock2.c
new file mode 100644
index 0000000000..4c8fb9f247
--- /dev/null
+++ b/time/tst-clock2.c
@@ -0,0 +1,43 @@
+/* Test setting the monotonic clock.  */
+
+#include <time.h>
+#include <unistd.h>
+
+#if defined CLOCK_MONOTONIC && defined _POSIX_MONOTONIC_CLOCK
+
+# include <errno.h>
+# include <stdio.h>
+
+static int
+do_test (void)
+{
+  if (sysconf (_SC_MONOTONIC_CLOCK) <= 0)
+    return 0;
+
+  struct timespec ts;
+  if (clock_gettime (CLOCK_MONOTONIC, &ts) != 0)
+    {
+      puts ("clock_gettime(CLOCK_MONOTONIC) failed");
+      return 1;
+    }
+
+  /* Setting the monotonic clock must fail.  */
+  if (clock_settime (CLOCK_MONOTONIC, &ts) != -1)
+    {
+      puts ("clock_settime(CLOCK_MONOTONIC) did not fail");
+      return 1;
+    }
+  if (errno != EINVAL)
+    {
+      printf ("clock_settime(CLOCK_MONOTONIC) set errno to %d, expected %d\n",
+	      errno, EINVAL);
+      return 1;
+    }
+  return 0;
+}
+# define TEST_FUNCTION do_test ()
+
+#else
+# define TEST_FUNCTION	0
+#endif
+#include "../test-skeleton.c"
diff --git a/time/tst-clock_nanosleep.c b/time/tst-clock_nanosleep.c
new file mode 100644
index 0000000000..f5df327e2f
--- /dev/null
+++ b/time/tst-clock_nanosleep.c
@@ -0,0 +1,57 @@
+/* Copyright (C) 2003-2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+
+
+/* Test that clock_nanosleep() does sleep.  */
+static int
+do_test (void)
+{
+  /* Current time.  */
+  struct timeval tv1;
+  (void) gettimeofday (&tv1, NULL);
+
+  struct timespec ts;
+  ts.tv_sec = 1;
+  ts.tv_nsec = 0;
+  TEMP_FAILURE_RETRY (clock_nanosleep (CLOCK_REALTIME, 0, &ts, &ts));
+
+  /* At least one second must have passed.  */
+  struct timeval tv2;
+  (void) gettimeofday (&tv2, NULL);
+
+  tv2.tv_sec -= tv1.tv_sec;
+  tv2.tv_usec -= tv1.tv_usec;
+  if (tv2.tv_usec < 0)
+    --tv2.tv_sec;
+
+  if (tv2.tv_sec < 1)
+    {
+      puts ("clock_nanosleep didn't sleep long enough");
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/time/tst-cpuclock1.c b/time/tst-cpuclock1.c
new file mode 100644
index 0000000000..e3f23aa307
--- /dev/null
+++ b/time/tst-cpuclock1.c
@@ -0,0 +1,320 @@
+/* Test program for process CPU clocks.
+   Copyright (C) 2004-2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdint.h>
+#include <sys/wait.h>
+
+/* This function is intended to rack up both user and system time.  */
+static void
+chew_cpu (void)
+{
+  while (1)
+    {
+      static volatile char buf[4096];
+      for (int i = 0; i < 100; ++i)
+	for (size_t j = 0; j < sizeof buf; ++j)
+	  buf[j] = 0xaa;
+      int nullfd = open ("/dev/null", O_WRONLY);
+      for (int i = 0; i < 100; ++i)
+	for (size_t j = 0; j < sizeof buf; ++j)
+	  buf[j] = 0xbb;
+      write (nullfd, (char *) buf, sizeof buf);
+      close (nullfd);
+      if (getppid () == 1)
+	_exit (2);
+    }
+}
+
+static int
+do_test (void)
+{
+  int result = 0;
+  clockid_t cl;
+  int e;
+  pid_t dead_child, child;
+
+  /* Fork a child and let it die, to give us a PID known not be valid
+     (assuming PIDs don't wrap around during the test).  */
+  {
+    dead_child = fork ();
+    if (dead_child == 0)
+      _exit (0);
+    if (dead_child < 0)
+      {
+	perror ("fork");
+	return 1;
+      }
+    int x;
+    if (wait (&x) != dead_child)
+      {
+	perror ("wait");
+	return 2;
+      }
+  }
+
+  /* POSIX says we should get ESRCH for this.  */
+  e = clock_getcpuclockid (dead_child, &cl);
+  if (e != ENOSYS && e != ESRCH && e != EPERM)
+    {
+      printf ("clock_getcpuclockid on dead PID %d => %s\n",
+	      dead_child, strerror (e));
+      result = 1;
+    }
+
+  /* Now give us a live child eating up CPU time.  */
+  child = fork ();
+  if (child == 0)
+    {
+      chew_cpu ();
+      _exit (1);
+    }
+  if (child < 0)
+    {
+      perror ("fork");
+      return 1;
+    }
+
+  e = clock_getcpuclockid (child, &cl);
+  if (e == EPERM)
+    {
+      puts ("clock_getcpuclockid does not support other processes");
+      goto done;
+    }
+  if (e != 0)
+    {
+      printf ("clock_getcpuclockid on live PID %d => %s\n",
+	      child, strerror (e));
+      result = 1;
+      goto done;
+    }
+
+  const clockid_t child_clock = cl;
+  struct timespec res;
+  if (clock_getres (child_clock, &res) < 0)
+    {
+      printf ("clock_getres on live PID %d clock %lx => %s\n",
+	      child, (unsigned long int) child_clock, strerror (errno));
+      result = 1;
+      goto done;
+    }
+  printf ("live PID %d clock %lx resolution %ju.%.9ju\n",
+	  child, (unsigned long int) child_clock,
+	  (uintmax_t) res.tv_sec, (uintmax_t) res.tv_nsec);
+
+  struct timespec before, after;
+  if (clock_gettime (child_clock, &before) < 0)
+    {
+      printf ("clock_gettime on live PID %d clock %lx => %s\n",
+	      child, (unsigned long int) child_clock, strerror (errno));
+      result = 1;
+      goto done;
+    }
+  /* Should be close to 0.0.  */
+  printf ("live PID %d before sleep => %ju.%.9ju\n",
+	  child, (uintmax_t) before.tv_sec, (uintmax_t) before.tv_nsec);
+
+  struct timespec sleeptime = { .tv_nsec = 500000000 };
+  if (nanosleep (&sleeptime, NULL) != 0)
+    {
+      perror ("nanosleep");
+      result = 1;
+      goto done;
+    }
+
+  if (clock_gettime (child_clock, &after) < 0)
+    {
+      printf ("clock_gettime on live PID %d clock %lx => %s\n",
+	      child, (unsigned long int) child_clock, strerror (errno));
+      result = 1;
+      goto done;
+    }
+  /* Should be close to 0.5.  */
+  printf ("live PID %d after sleep => %ju.%.9ju\n",
+	  child, (uintmax_t) after.tv_sec, (uintmax_t) after.tv_nsec);
+
+  struct timespec diff = { .tv_sec = after.tv_sec - before.tv_sec,
+			   .tv_nsec = after.tv_nsec - before.tv_nsec };
+  if (diff.tv_nsec < 0)
+    {
+      --diff.tv_sec;
+      diff.tv_nsec += 1000000000;
+    }
+  if (diff.tv_sec != 0
+      || diff.tv_nsec > 600000000
+      || diff.tv_nsec < 100000000)
+    {
+      printf ("before - after %ju.%.9ju outside reasonable range\n",
+	      (uintmax_t) diff.tv_sec, (uintmax_t) diff.tv_nsec);
+      result = 1;
+    }
+
+  sleeptime.tv_nsec = 100000000;
+  e = clock_nanosleep (child_clock, 0, &sleeptime, NULL);
+  if (e == EINVAL || e == ENOTSUP || e == ENOSYS)
+    {
+      printf ("clock_nanosleep not supported for other process clock: %s\n",
+	      strerror (e));
+    }
+  else if (e != 0)
+    {
+      printf ("clock_nanosleep on other process clock: %s\n", strerror (e));
+      result = 1;
+    }
+  else
+    {
+      struct timespec afterns;
+      if (clock_gettime (child_clock, &afterns) < 0)
+	{
+	  printf ("clock_gettime on live PID %d clock %lx => %s\n",
+		  child, (unsigned long int) child_clock, strerror (errno));
+	  result = 1;
+	}
+      else
+	{
+	  struct timespec d = { .tv_sec = afterns.tv_sec - after.tv_sec,
+				.tv_nsec = afterns.tv_nsec - after.tv_nsec };
+	  if (d.tv_nsec < 0)
+	    {
+	      --d.tv_sec;
+	      d.tv_nsec += 1000000000;
+	    }
+	  if (d.tv_sec > 0
+	      || d.tv_nsec < sleeptime.tv_nsec
+	      || d.tv_nsec > sleeptime.tv_nsec * 2)
+	    {
+	      printf ("nanosleep time %ju.%.9ju outside reasonable range\n",
+		      (uintmax_t) d.tv_sec, (uintmax_t) d.tv_nsec);
+	      result = 1;
+	    }
+	}
+    }
+
+  if (kill (child, SIGKILL) != 0)
+    {
+      perror ("kill");
+      result = 2;
+      goto done;
+    }
+
+  /* Wait long enough to let the child finish dying.  */
+
+  sleeptime.tv_nsec = 200000000;
+  if (nanosleep (&sleeptime, NULL) != 0)
+    {
+      perror ("nanosleep");
+      result = 1;
+      goto done;
+    }
+
+  struct timespec dead;
+  if (clock_gettime (child_clock, &dead) < 0)
+    {
+      printf ("clock_gettime on dead PID %d clock %lx => %s\n",
+	      child, (unsigned long int) child_clock, strerror (errno));
+      result = 1;
+      goto done;
+    }
+  /* Should be close to 0.6.  */
+  printf ("dead PID %d => %ju.%.9ju\n",
+	  child, (uintmax_t) dead.tv_sec, (uintmax_t) dead.tv_nsec);
+
+  diff.tv_sec = dead.tv_sec - after.tv_sec;
+  diff.tv_nsec = dead.tv_nsec - after.tv_nsec;
+  if (diff.tv_nsec < 0)
+    {
+      --diff.tv_sec;
+      diff.tv_nsec += 1000000000;
+    }
+  if (diff.tv_sec != 0 || diff.tv_nsec > 200000000)
+    {
+      printf ("dead - after %ju.%.9ju outside reasonable range\n",
+	      (uintmax_t) diff.tv_sec, (uintmax_t) diff.tv_nsec);
+      result = 1;
+    }
+
+  /* Now reap the child and verify that its clock is no longer valid.  */
+  {
+    int x;
+    if (waitpid (child, &x, 0) != child)
+      {
+	perror ("waitpid");
+	result = 1;
+      }
+  }
+
+  if (clock_gettime (child_clock, &dead) == 0)
+    {
+      printf ("clock_gettime on reaped PID %d clock %lx => %ju%.9ju\n",
+	      child, (unsigned long int) child_clock,
+	      (uintmax_t) dead.tv_sec, (uintmax_t) dead.tv_nsec);
+      result = 1;
+    }
+  else
+    {
+      if (errno != EINVAL)
+	result = 1;
+      printf ("clock_gettime on reaped PID %d clock %lx => %s\n",
+	      child, (unsigned long int) child_clock, strerror (errno));
+    }
+
+  if (clock_getres (child_clock, &dead) == 0)
+    {
+      printf ("clock_getres on reaped PID %d clock %lx => %ju%.9ju\n",
+	      child, (unsigned long int) child_clock,
+	      (uintmax_t) dead.tv_sec, (uintmax_t) dead.tv_nsec);
+      result = 1;
+    }
+  else
+    {
+      if (errno != EINVAL)
+	result = 1;
+      printf ("clock_getres on reaped PID %d clock %lx => %s\n",
+	      child, (unsigned long int) child_clock, strerror (errno));
+    }
+
+  return result;
+
+ done:
+  {
+    if (kill (child, SIGKILL) != 0 && errno != ESRCH)
+      {
+	perror ("kill");
+	return 2;
+      }
+    int x;
+    if (waitpid (child, &x, 0) != child && errno != ECHILD)
+      {
+	perror ("waitpid");
+	return 2;
+      }
+  }
+
+  return result;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"