aboutsummaryrefslogtreecommitdiff
path: root/time
diff options
context:
space:
mode:
authorZack Weinberg <zackw@panix.com>2019-09-04 08:18:57 +0200
committerFlorian Weimer <fweimer@redhat.com>2019-09-04 14:39:38 +0200
commit7b5af2d8f2a2b858319a792678b15a0db08764c7 (patch)
tree014a27968a65aaadedc097d9fe9bd1fb62c45896 /time
parentb5367a08ae810e3c648fb036f2e5766204f9d83f (diff)
downloadglibc-7b5af2d8f2a2b858319a792678b15a0db08764c7.zip
glibc-7b5af2d8f2a2b858319a792678b15a0db08764c7.tar.gz
glibc-7b5af2d8f2a2b858319a792678b15a0db08764c7.tar.bz2
Finish move of clock_* functions to libc. [BZ #24959]
In glibc 2.17, the functions clock_getcpuclockid, clock_getres, clock_gettime, clock_nanosleep, and clock_settime were moved from librt.so to libc.so, leaving compatibility stubs behind. Now that the dynamic linker no longer insists on finding versioned symbols in the same library that originally defined them, we do not need the stubs anymore, and this means we don't need GLIBC_PRIVATE __-prefix aliases for most of the functions anymore either. (clock_gettime still needs one.) For ports added before 2.17, libc.so needs to provide two symbol versions for each, the default at GLIBC_2.17 plus a compat version matching what librt had. While I'm at it, move the clock_*.c files and their tests from rt/ to time/.
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 a428f55..85a62c0 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 fd83818..8788e19 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 0000000..8d205ab
--- /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 0000000..412f80f
--- /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 0000000..92c6081
--- /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 0000000..c53c820
--- /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 0000000..dd86a1c
--- /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 0000000..2e19bb1
--- /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 0000000..4c8fb9f
--- /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 0000000..f5df327
--- /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 0000000..e3f23aa
--- /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"