Message ID | 685b5889-5044-13eb-f93c-68e15b0cd467@redhat.com |
---|---|
State | New |
Headers | show |
Series | Add tests of time, gettimeofday, clock_gettime | expand |
* Joseph Myers: > + /* Also verify that after sleeping, the time returned has > + increased. Repeat several times to verify that each time, > + the time from the time function is truncated not rounded. > + For CPU time clocks, the time spent spinning on the CPU, and > + so whether we end in the later half of a second, is not > + predictable; thus, only test once for those clocks. */ > + const struct timespec duration = { .tv_nsec = 100000000 }; > + for (int j = 0; j < 5; j++) > + { > + if (clocks[i].is_cputime) > + for (volatile unsigned int x = 0; x != (unsigned int) -1; x++) > + ; > + else > + { > + ret = nanosleep (&duration, NULL); > + TEST_VERIFY_EXIT (ret == 0); > + } > + t1 = time (NULL); > + TEST_VERIFY_EXIT (t1 != (time_t) -1); > + ret = clock_gettime (clocks[i].clockid, &ts3); > + TEST_VERIFY_EXIT (ret == 0); > + TEST_VERIFY (compare_timespec (&ts2, &ts3) < 0); > + if (clocks[i].clockid == CLOCK_REALTIME) > + TEST_VERIFY (t1 <= ts3.tv_sec); Is this check (for truncation) really correct? We have a bug report that it actually has a certain failure rate: time sometimes appears to go backwards <https://sourceware.org/bugzilla/show_bug.cgi?id=30200> I think there is (de facto) some double-rounding going on here. Thanks, Florian
On Mon, 28 Oct 2024, Florian Weimer wrote: > > + t1 = time (NULL); > > + TEST_VERIFY_EXIT (t1 != (time_t) -1); > > + ret = clock_gettime (clocks[i].clockid, &ts3); > > + TEST_VERIFY_EXIT (ret == 0); > > + TEST_VERIFY (compare_timespec (&ts2, &ts3) < 0); > > + if (clocks[i].clockid == CLOCK_REALTIME) > > + TEST_VERIFY (t1 <= ts3.tv_sec); > > Is this check (for truncation) really correct? We have a bug report > that it actually has a certain failure rate: > > time sometimes appears to go backwards > <https://sourceware.org/bugzilla/show_bug.cgi?id=30200> > > I think there is (de facto) some double-rounding going on here. That bug appears to be a different issue: it's calling time *after* clock_gettime and getting a result that might be up to 1.01 seconds before that returned from clock_gettime. My tests call time *before* clock_gettime and verify the result is no later than that returned by clock_gettime (or gettimeofday), so a time that is 1.01 seconds old would not make these tests fail; they're checking that the result is not rounded up, rather than by how much it's rounded down.
* Joseph Myers: > + /* Also verify that after sleeping, the time returned has > + increased. Repeat several times to verify that each time, > + the time from the time function is truncated not rounded. > + For CPU time clocks, the time spent spinning on the CPU, and > + so whether we end in the later half of a second, is not > + predictable; thus, only test once for those clocks. */ > + const struct timespec duration = { .tv_nsec = 100000000 }; > + for (int j = 0; j < 5; j++) > + { > + if (clocks[i].is_cputime) > + for (volatile unsigned int x = 0; x != (unsigned int) -1; x++) > + ; > +#define TIMEOUT 60 I think this implicitly requires an 1 GHz CPU (or one with store-load propagation): The loop needs about three memory accesses, executes 5 times, so 15 * 2**32 memory operations. It has 60 seconds to complete (less due to the other tests), so we end up with having to execute roughly one billion memory operations per second. Maybe make the loop shorter? Or add some sort of calibration? Exit the loop use alarm instead of a count? (Or would that interfere with the test objective?) Or do we expect people to use TIMEOUTFACTOR on slower CPUs anyway? Rest looks good. Thanks, Florian
On Tue, 29 Oct 2024, Florian Weimer wrote: > * Joseph Myers: > > > + /* Also verify that after sleeping, the time returned has > > + increased. Repeat several times to verify that each time, > > + the time from the time function is truncated not rounded. > > + For CPU time clocks, the time spent spinning on the CPU, and > > + so whether we end in the later half of a second, is not > > + predictable; thus, only test once for those clocks. */ > > + const struct timespec duration = { .tv_nsec = 100000000 }; > > + for (int j = 0; j < 5; j++) > > + { > > + if (clocks[i].is_cputime) > > + for (volatile unsigned int x = 0; x != (unsigned int) -1; x++) > > + ; > > > +#define TIMEOUT 60 > > I think this implicitly requires an 1 GHz CPU (or one with store-load > propagation): The loop needs about three memory accesses, executes 5 > times, so 15 * 2**32 memory operations. It has 60 seconds to complete > (less due to the other tests), so we end up with having to execute > roughly one billion memory operations per second. > > Maybe make the loop shorter? Or add some sort of calibration? Exit the > loop use alarm instead of a count? (Or would that interfere with the > test objective?) Or do we expect people to use TIMEOUTFACTOR on slower > CPUs anyway? Here is a patch version using an alarm instead of a count. (Calibration would be problematic as a solution since it would presuppose there is working clock_gettime for a cputime clock, which is exactly what is being tested here. An alarm seems less likely to be an issue with the test objective; if the alarm raises the signal too soon or not at all, that should cause the test to fail; it only succeeds if the measured cputime clock goes forward as intended.) Add tests of time, gettimeofday, clock_gettime There are no tests specifically focused on the functions time, gettimeofday and clock_gettime, although there are some incidental uses in tests of other functions. Add tests specifically for these three functions. Tested for x86_64 and x86. --- Changed in v2: allow clock_gettime to fail with CLOCK_REALTIME_ALARM and CLOCK_BOOTTIME_ALARM. It appears these can fail on some system configurations, in particular those used by Linaro CI for both AArch64 and Arm. Changed in v3: use a timer rather than a fixed number of iterations to end the loop spinning eating CPU time. diff --git a/time/Makefile b/time/Makefile index d06797b06c..de22692683 100644 --- a/time/Makefile +++ b/time/Makefile @@ -53,6 +53,7 @@ tests := \ tst-adjtime \ tst-clock \ tst-clock2 \ + tst-clock_gettime \ tst-clock_nanosleep \ tst-clock_settime \ tst-cpuclock1 \ @@ -61,6 +62,7 @@ tests := \ tst-ftime \ tst-ftime_l \ tst-getdate \ + tst-gettimeofday \ tst-gmtime \ tst-itimer \ tst-mktime \ @@ -77,6 +79,7 @@ tests := \ tst-strptime-whitespace \ tst-strptime2 \ tst-strptime3 \ + tst-time \ tst-timegm \ tst-timespec_get \ tst-timespec_getres \ @@ -90,16 +93,19 @@ tests-time64 := \ tst-adjtime-time64 \ tst-clock-time64 \ tst-clock2-time64 \ + tst-clock_gettime-time64 \ tst-clock_nanosleep-time64 \ tst-clock_settime-time64 \ tst-cpuclock1-time64 \ tst-ctime-time64 \ tst-difftime-time64 \ + tst-gettimeofday-time64 \ tst-gmtime-time64 \ tst-itimer-time64 \ tst-mktime4-time64 \ tst-settimeofday-time64 \ tst-strftime4-time64 \ + tst-time-time64 \ tst-timegm-time64 \ tst-timespec_get-time64 \ tst-timespec_getres-time64 \ diff --git a/time/tst-clock_gettime-time64.c b/time/tst-clock_gettime-time64.c new file mode 100644 index 0000000000..5b215d11f8 --- /dev/null +++ b/time/tst-clock_gettime-time64.c @@ -0,0 +1 @@ +#include "tst-clock_gettime.c" diff --git a/time/tst-clock_gettime.c b/time/tst-clock_gettime.c new file mode 100644 index 0000000000..51f24c0be2 --- /dev/null +++ b/time/tst-clock_gettime.c @@ -0,0 +1,184 @@ +/* Test clock_gettime function. + Copyright (C) 2024 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 + <https://www.gnu.org/licenses/>. */ + +#include <stdbool.h> +#include <stdio.h> +#include <time.h> + +#include <support/check.h> +#include <support/test-driver.h> +#include <support/xsignal.h> + +/* Compare two struct timespec values, returning a value -1, 0 or 1. */ + +int +compare_timespec (const struct timespec *tv1, const struct timespec *tv2) +{ + if (tv1->tv_sec < tv2->tv_sec) + return -1; + if (tv1->tv_sec > tv2->tv_sec) + return 1; + if (tv1->tv_nsec < tv2->tv_nsec) + return -1; + if (tv1->tv_nsec > tv2->tv_nsec) + return 1; + return 0; +} + +struct test_clockid +{ + clockid_t clockid; + const char *name; + bool is_cputime; + bool fail_ok; +}; + +#define CLOCK(clockid) { clockid, # clockid, false, false } +#define CLOCK_CPU(clockid) { clockid, # clockid, true, false } +#define CLOCK_FAIL_OK(clockid) { clockid, # clockid, false, true } + +static const struct test_clockid clocks[] = + { + CLOCK (CLOCK_REALTIME), +#ifdef CLOCK_MONOTONIC + CLOCK (CLOCK_MONOTONIC), +#endif +#ifdef CLOCK_PROCESS_CPUTIME_ID + CLOCK_CPU (CLOCK_PROCESS_CPUTIME_ID), +#endif +#ifdef CLOCK_THREAD_CPUTIME_ID + CLOCK_CPU (CLOCK_THREAD_CPUTIME_ID), +#endif +#ifdef CLOCK_MONOTONIC_RAW + CLOCK (CLOCK_MONOTONIC_RAW), +#endif +#ifdef CLOCK_REALTIME_COARSE + CLOCK (CLOCK_REALTIME_COARSE), +#endif +#ifdef CLOCK_MONOTONIC_COARSE + CLOCK (CLOCK_MONOTONIC_COARSE), +#endif +#ifdef CLOCK_BOOTTIME + CLOCK (CLOCK_BOOTTIME), +#endif +#ifdef CLOCK_REALTIME_ALARM + CLOCK_FAIL_OK (CLOCK_REALTIME_ALARM), +#endif +#ifdef CLOCK_BOOTTIME_ALARM + CLOCK_FAIL_OK (CLOCK_BOOTTIME_ALARM), +#endif +#ifdef CLOCK_TAI + CLOCK (CLOCK_TAI), +#endif + }; + + +volatile int sigalrm_received; + +void +handle_sigalrm (int sig) +{ + sigalrm_received = 1; +} + +int +do_test (void) +{ + /* Verify that the calls to clock_gettime succeed, that the time does + not decrease, and that time returns a truncated (not rounded) + version of the time. */ + for (size_t i = 0; i < sizeof clocks / sizeof clocks[0]; i++) + { + printf ("testing %s\n", clocks[i].name); + struct timespec ts1, ts2, ts3; + int ret; + time_t t1; + t1 = time (NULL); + TEST_VERIFY_EXIT (t1 != (time_t) -1); + ret = clock_gettime (clocks[i].clockid, &ts1); + if (clocks[i].fail_ok && ret == -1) + { + printf ("failed (OK for this clock): %m\n"); + continue; + } + TEST_VERIFY_EXIT (ret == 0); + if (clocks[i].clockid == CLOCK_REALTIME) + TEST_VERIFY (t1 <= ts1.tv_sec); + TEST_VERIFY (ts1.tv_nsec >= 0); + TEST_VERIFY (ts1.tv_nsec < 1000000000); + ret = clock_gettime (clocks[i].clockid, &ts2); + TEST_VERIFY_EXIT (ret == 0); + TEST_VERIFY (compare_timespec (&ts1, &ts2) <= 0); + TEST_VERIFY (ts2.tv_nsec >= 0); + TEST_VERIFY (ts2.tv_nsec < 1000000000); + /* Also verify that after sleeping, the time returned has + increased. Repeat several times to verify that each time, + the time from the time function is truncated not rounded. + For CPU time clocks, the time spent spinning on the CPU, and + so whether we end in the later half of a second, is not + predictable; thus, only test once for those clocks. */ + const struct timespec duration = { .tv_nsec = 100000000 }; + for (int j = 0; j < 5; j++) + { + if (clocks[i].is_cputime) + { + timer_t timer; + ret = timer_create (CLOCK_PROCESS_CPUTIME_ID, NULL, &timer); + TEST_VERIFY_EXIT (ret == 0); + sigalrm_received = 0; + xsignal (SIGALRM, handle_sigalrm); + struct itimerspec t = + { .it_value = + { + .tv_sec = 0, + .tv_nsec = 200000000 + } + }; + ret = timer_settime (timer, 0, &t, NULL); + TEST_VERIFY_EXIT (ret == 0); + while (sigalrm_received == 0) + ; + xsignal (SIGALRM, SIG_DFL); + ret = timer_delete (timer); + TEST_VERIFY_EXIT (ret == 0); + } + else + { + ret = nanosleep (&duration, NULL); + TEST_VERIFY_EXIT (ret == 0); + } + t1 = time (NULL); + TEST_VERIFY_EXIT (t1 != (time_t) -1); + ret = clock_gettime (clocks[i].clockid, &ts3); + TEST_VERIFY_EXIT (ret == 0); + TEST_VERIFY (compare_timespec (&ts2, &ts3) < 0); + if (clocks[i].clockid == CLOCK_REALTIME) + TEST_VERIFY (t1 <= ts3.tv_sec); + TEST_VERIFY (ts3.tv_nsec >= 0); + TEST_VERIFY (ts3.tv_nsec < 1000000000); + ts2 = ts3; + if (clocks[i].is_cputime) + break; + } + } + return 0; +} + +#define TIMEOUT 60 + +#include <support/test-driver.c> diff --git a/time/tst-gettimeofday-time64.c b/time/tst-gettimeofday-time64.c new file mode 100644 index 0000000000..6c08761ef9 --- /dev/null +++ b/time/tst-gettimeofday-time64.c @@ -0,0 +1 @@ +#include "tst-gettimeofday.c" diff --git a/time/tst-gettimeofday.c b/time/tst-gettimeofday.c new file mode 100644 index 0000000000..978ae28587 --- /dev/null +++ b/time/tst-gettimeofday.c @@ -0,0 +1,93 @@ +/* Test gettimeofday function. + Copyright (C) 2024 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 + <https://www.gnu.org/licenses/>. */ + +#include <sys/time.h> +#include <time.h> + +#include <support/check.h> +#include <support/test-driver.h> + +/* Compare two struct timeval values, returning a value -1, 0 or 1. */ + +int +compare_timeval (const struct timeval *tv1, const struct timeval *tv2) +{ + if (tv1->tv_sec < tv2->tv_sec) + return -1; + if (tv1->tv_sec > tv2->tv_sec) + return 1; + if (tv1->tv_usec < tv2->tv_usec) + return -1; + if (tv1->tv_usec > tv2->tv_usec) + return 1; + return 0; +} + +int +do_test (void) +{ + struct timeval tv1, tv2, tv3; + int ret; + time_t t1; + /* Verify that the calls to gettimeofday succeed, that the time does + not decrease, and that time returns a truncated (not rounded) + version of the time. */ + t1 = time (NULL); + TEST_VERIFY_EXIT (t1 != (time_t) -1); + ret = gettimeofday (&tv1, NULL); + TEST_VERIFY_EXIT (ret == 0); + TEST_VERIFY (t1 <= tv1.tv_sec); + TEST_VERIFY (tv1.tv_usec >= 0); + TEST_VERIFY (tv1.tv_usec < 1000000); + ret = gettimeofday (&tv2, NULL); + TEST_VERIFY_EXIT (ret == 0); + TEST_VERIFY (compare_timeval (&tv1, &tv2) <= 0); + TEST_VERIFY (tv2.tv_usec >= 0); + TEST_VERIFY (tv2.tv_usec < 1000000); + /* Also verify that after sleeping, the time returned has increased. + Repeat several times to verify that each time, the time from the + time function is truncated not rounded. */ + const struct timespec duration = { .tv_nsec = 100000000 }; + for (int i = 0; i < 10; i++) + { + ret = nanosleep (&duration, NULL); + TEST_VERIFY_EXIT (ret == 0); + t1 = time (NULL); + TEST_VERIFY_EXIT (t1 != (time_t) -1); + ret = gettimeofday (&tv3, NULL); + TEST_VERIFY_EXIT (ret == 0); + TEST_VERIFY (compare_timeval (&tv2, &tv3) < 0); + TEST_VERIFY (t1 <= tv3.tv_sec); + TEST_VERIFY (tv3.tv_usec >= 0); + TEST_VERIFY (tv3.tv_usec < 1000000); + tv2 = tv3; + } + /* Also test with the obsolete tz argument not being NULL. */ + struct timezone tz = { 0 }; + t1 = time (NULL); + TEST_VERIFY_EXIT (t1 != (time_t) -1); + ret = gettimeofday (&tv3, &tz); + TEST_VERIFY_EXIT (ret == 0); + TEST_VERIFY (t1 <= tv3.tv_sec); + TEST_VERIFY (compare_timeval (&tv2, &tv3) <= 0); + TEST_VERIFY (tv3.tv_usec >= 0); + TEST_VERIFY (tv3.tv_usec < 1000000); + return 0; +} + +#include <support/test-driver.c> diff --git a/time/tst-time-time64.c b/time/tst-time-time64.c new file mode 100644 index 0000000000..30e8d3c86e --- /dev/null +++ b/time/tst-time-time64.c @@ -0,0 +1 @@ +#include "tst-time.c" diff --git a/time/tst-time.c b/time/tst-time.c new file mode 100644 index 0000000000..7f24bed353 --- /dev/null +++ b/time/tst-time.c @@ -0,0 +1,51 @@ +/* Test time function. + Copyright (C) 2024 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 + <https://www.gnu.org/licenses/>. */ + +#include <time.h> +#include <unistd.h> + +#include <support/check.h> +#include <support/test-driver.h> + +int +do_test (void) +{ + time_t t1, t2, t3, t4, t5, t6; + /* Verify that the calls to time succeed, that the value returned + directly equals that returned through the pointer passed, and + that the time does not decrease. */ + t1 = time (&t2); + TEST_VERIFY_EXIT (t1 != (time_t) -1); + TEST_VERIFY (t1 == t2); + t3 = time (NULL); + TEST_VERIFY_EXIT (t3 != (time_t) -1); + TEST_VERIFY (t3 >= t1); + /* Also verify that after sleeping, the time returned has + increased. */ + sleep (2); + t4 = time (&t5); + TEST_VERIFY_EXIT (t4 != (time_t) -1); + TEST_VERIFY (t4 == t5); + TEST_VERIFY (t4 > t3); + t6 = time (NULL); + TEST_VERIFY_EXIT (t6 != (time_t) -1); + TEST_VERIFY (t6 >= t4); + return 0; +} + +#include <support/test-driver.c>
* Joseph Myers: > Here is a patch version using an alarm instead of a count. (Calibration > would be problematic as a solution since it would presuppose there is > working clock_gettime for a cputime clock, which is exactly what is being > tested here. An alarm seems less likely to be an issue with the test > objective; if the alarm raises the signal too soon or not at all, that > should cause the test to fail; it only succeeds if the measured cputime > clock goes forward as intended.) > > > > Add tests of time, gettimeofday, clock_gettime > > There are no tests specifically focused on the functions time, > gettimeofday and clock_gettime, although there are some incidental > uses in tests of other functions. Add tests specifically for these > three functions. > > Tested for x86_64 and x86. This version looks good to me. Reviewed-by: Florian Weimer <fweimer@redhat.com> Thanks, Florian
diff --git a/time/Makefile b/time/Makefile index d06797b06c..de22692683 100644 --- a/time/Makefile +++ b/time/Makefile @@ -53,6 +53,7 @@ tests := \ tst-adjtime \ tst-clock \ tst-clock2 \ + tst-clock_gettime \ tst-clock_nanosleep \ tst-clock_settime \ tst-cpuclock1 \ @@ -61,6 +62,7 @@ tests := \ tst-ftime \ tst-ftime_l \ tst-getdate \ + tst-gettimeofday \ tst-gmtime \ tst-itimer \ tst-mktime \ @@ -77,6 +79,7 @@ tests := \ tst-strptime-whitespace \ tst-strptime2 \ tst-strptime3 \ + tst-time \ tst-timegm \ tst-timespec_get \ tst-timespec_getres \ @@ -90,16 +93,19 @@ tests-time64 := \ tst-adjtime-time64 \ tst-clock-time64 \ tst-clock2-time64 \ + tst-clock_gettime-time64 \ tst-clock_nanosleep-time64 \ tst-clock_settime-time64 \ tst-cpuclock1-time64 \ tst-ctime-time64 \ tst-difftime-time64 \ + tst-gettimeofday-time64 \ tst-gmtime-time64 \ tst-itimer-time64 \ tst-mktime4-time64 \ tst-settimeofday-time64 \ tst-strftime4-time64 \ + tst-time-time64 \ tst-timegm-time64 \ tst-timespec_get-time64 \ tst-timespec_getres-time64 \ diff --git a/time/tst-clock_gettime-time64.c b/time/tst-clock_gettime-time64.c new file mode 100644 index 0000000000..5b215d11f8 --- /dev/null +++ b/time/tst-clock_gettime-time64.c @@ -0,0 +1 @@ +#include "tst-clock_gettime.c" diff --git a/time/tst-clock_gettime.c b/time/tst-clock_gettime.c new file mode 100644 index 0000000000..4bb92fc4b2 --- /dev/null +++ b/time/tst-clock_gettime.c @@ -0,0 +1,148 @@ +/* Test clock_gettime function. + Copyright (C) 2024 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 + <https://www.gnu.org/licenses/>. */ + +#include <stdbool.h> +#include <stdio.h> +#include <time.h> + +#include <support/check.h> +#include <support/test-driver.h> + +/* Compare two struct timespec values, returning a value -1, 0 or 1. */ + +int +compare_timespec (const struct timespec *tv1, const struct timespec *tv2) +{ + if (tv1->tv_sec < tv2->tv_sec) + return -1; + if (tv1->tv_sec > tv2->tv_sec) + return 1; + if (tv1->tv_nsec < tv2->tv_nsec) + return -1; + if (tv1->tv_nsec > tv2->tv_nsec) + return 1; + return 0; +} + +struct test_clockid +{ + clockid_t clockid; + const char *name; + bool is_cputime; +}; + +#define CLOCK(clockid) { clockid, # clockid, false } +#define CLOCK_CPU(clockid) { clockid, # clockid, true } + +static const struct test_clockid clocks[] = + { + CLOCK (CLOCK_REALTIME), +#ifdef CLOCK_MONOTONIC + CLOCK (CLOCK_MONOTONIC), +#endif +#ifdef CLOCK_PROCESS_CPUTIME_ID + CLOCK_CPU (CLOCK_PROCESS_CPUTIME_ID), +#endif +#ifdef CLOCK_THREAD_CPUTIME_ID + CLOCK_CPU (CLOCK_THREAD_CPUTIME_ID), +#endif +#ifdef CLOCK_MONOTONIC_RAW + CLOCK (CLOCK_MONOTONIC_RAW), +#endif +#ifdef CLOCK_REALTIME_COARSE + CLOCK (CLOCK_REALTIME_COARSE), +#endif +#ifdef CLOCK_MONOTONIC_COARSE + CLOCK (CLOCK_MONOTONIC_COARSE), +#endif +#ifdef CLOCK_BOOTTIME + CLOCK (CLOCK_BOOTTIME), +#endif +#ifdef CLOCK_REALTIME_ALARM + CLOCK (CLOCK_REALTIME_ALARM), +#endif +#ifdef CLOCK_BOOTTIME_ALARM + CLOCK (CLOCK_BOOTTIME_ALARM), +#endif +#ifdef CLOCK_TAI + CLOCK (CLOCK_TAI), +#endif + }; + +int +do_test (void) +{ + /* Verify that the calls to clock_gettime succeed, that the time does + not decrease, and that time returns a truncated (not rounded) + version of the time. */ + for (size_t i = 0; i < sizeof clocks / sizeof clocks[0]; i++) + { + printf ("testing %s\n", clocks[i].name); + struct timespec ts1, ts2, ts3; + int ret; + time_t t1; + t1 = time (NULL); + TEST_VERIFY_EXIT (t1 != (time_t) -1); + ret = clock_gettime (clocks[i].clockid, &ts1); + TEST_VERIFY_EXIT (ret == 0); + if (clocks[i].clockid == CLOCK_REALTIME) + TEST_VERIFY (t1 <= ts1.tv_sec); + TEST_VERIFY (ts1.tv_nsec >= 0); + TEST_VERIFY (ts1.tv_nsec < 1000000000); + ret = clock_gettime (clocks[i].clockid, &ts2); + TEST_VERIFY_EXIT (ret == 0); + TEST_VERIFY (compare_timespec (&ts1, &ts2) <= 0); + TEST_VERIFY (ts2.tv_nsec >= 0); + TEST_VERIFY (ts2.tv_nsec < 1000000000); + /* Also verify that after sleeping, the time returned has + increased. Repeat several times to verify that each time, + the time from the time function is truncated not rounded. + For CPU time clocks, the time spent spinning on the CPU, and + so whether we end in the later half of a second, is not + predictable; thus, only test once for those clocks. */ + const struct timespec duration = { .tv_nsec = 100000000 }; + for (int j = 0; j < 5; j++) + { + if (clocks[i].is_cputime) + for (volatile unsigned int x = 0; x != (unsigned int) -1; x++) + ; + else + { + ret = nanosleep (&duration, NULL); + TEST_VERIFY_EXIT (ret == 0); + } + t1 = time (NULL); + TEST_VERIFY_EXIT (t1 != (time_t) -1); + ret = clock_gettime (clocks[i].clockid, &ts3); + TEST_VERIFY_EXIT (ret == 0); + TEST_VERIFY (compare_timespec (&ts2, &ts3) < 0); + if (clocks[i].clockid == CLOCK_REALTIME) + TEST_VERIFY (t1 <= ts3.tv_sec); + TEST_VERIFY (ts3.tv_nsec >= 0); + TEST_VERIFY (ts3.tv_nsec < 1000000000); + ts2 = ts3; + if (clocks[i].is_cputime) + break; + } + } + return 0; +} + +#define TIMEOUT 60 + +#include <support/test-driver.c> diff --git a/time/tst-gettimeofday-time64.c b/time/tst-gettimeofday-time64.c new file mode 100644 index 0000000000..6c08761ef9 --- /dev/null +++ b/time/tst-gettimeofday-time64.c @@ -0,0 +1 @@ +#include "tst-gettimeofday.c" diff --git a/time/tst-gettimeofday.c b/time/tst-gettimeofday.c new file mode 100644 index 0000000000..978ae28587 --- /dev/null +++ b/time/tst-gettimeofday.c @@ -0,0 +1,93 @@ +/* Test gettimeofday function. + Copyright (C) 2024 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 + <https://www.gnu.org/licenses/>. */ + +#include <sys/time.h> +#include <time.h> + +#include <support/check.h> +#include <support/test-driver.h> + +/* Compare two struct timeval values, returning a value -1, 0 or 1. */ + +int +compare_timeval (const struct timeval *tv1, const struct timeval *tv2) +{ + if (tv1->tv_sec < tv2->tv_sec) + return -1; + if (tv1->tv_sec > tv2->tv_sec) + return 1; + if (tv1->tv_usec < tv2->tv_usec) + return -1; + if (tv1->tv_usec > tv2->tv_usec) + return 1; + return 0; +} + +int +do_test (void) +{ + struct timeval tv1, tv2, tv3; + int ret; + time_t t1; + /* Verify that the calls to gettimeofday succeed, that the time does + not decrease, and that time returns a truncated (not rounded) + version of the time. */ + t1 = time (NULL); + TEST_VERIFY_EXIT (t1 != (time_t) -1); + ret = gettimeofday (&tv1, NULL); + TEST_VERIFY_EXIT (ret == 0); + TEST_VERIFY (t1 <= tv1.tv_sec); + TEST_VERIFY (tv1.tv_usec >= 0); + TEST_VERIFY (tv1.tv_usec < 1000000); + ret = gettimeofday (&tv2, NULL); + TEST_VERIFY_EXIT (ret == 0); + TEST_VERIFY (compare_timeval (&tv1, &tv2) <= 0); + TEST_VERIFY (tv2.tv_usec >= 0); + TEST_VERIFY (tv2.tv_usec < 1000000); + /* Also verify that after sleeping, the time returned has increased. + Repeat several times to verify that each time, the time from the + time function is truncated not rounded. */ + const struct timespec duration = { .tv_nsec = 100000000 }; + for (int i = 0; i < 10; i++) + { + ret = nanosleep (&duration, NULL); + TEST_VERIFY_EXIT (ret == 0); + t1 = time (NULL); + TEST_VERIFY_EXIT (t1 != (time_t) -1); + ret = gettimeofday (&tv3, NULL); + TEST_VERIFY_EXIT (ret == 0); + TEST_VERIFY (compare_timeval (&tv2, &tv3) < 0); + TEST_VERIFY (t1 <= tv3.tv_sec); + TEST_VERIFY (tv3.tv_usec >= 0); + TEST_VERIFY (tv3.tv_usec < 1000000); + tv2 = tv3; + } + /* Also test with the obsolete tz argument not being NULL. */ + struct timezone tz = { 0 }; + t1 = time (NULL); + TEST_VERIFY_EXIT (t1 != (time_t) -1); + ret = gettimeofday (&tv3, &tz); + TEST_VERIFY_EXIT (ret == 0); + TEST_VERIFY (t1 <= tv3.tv_sec); + TEST_VERIFY (compare_timeval (&tv2, &tv3) <= 0); + TEST_VERIFY (tv3.tv_usec >= 0); + TEST_VERIFY (tv3.tv_usec < 1000000); + return 0; +} + +#include <support/test-driver.c> diff --git a/time/tst-time-time64.c b/time/tst-time-time64.c new file mode 100644 index 0000000000..30e8d3c86e --- /dev/null +++ b/time/tst-time-time64.c @@ -0,0 +1 @@ +#include "tst-time.c" diff --git a/time/tst-time.c b/time/tst-time.c new file mode 100644 index 0000000000..7f24bed353 --- /dev/null +++ b/time/tst-time.c @@ -0,0 +1,51 @@ +/* Test time function. + Copyright (C) 2024 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 + <https://www.gnu.org/licenses/>. */ + +#include <time.h> +#include <unistd.h> + +#include <support/check.h> +#include <support/test-driver.h> + +int +do_test (void) +{ + time_t t1, t2, t3, t4, t5, t6; + /* Verify that the calls to time succeed, that the value returned + directly equals that returned through the pointer passed, and + that the time does not decrease. */ + t1 = time (&t2); + TEST_VERIFY_EXIT (t1 != (time_t) -1); + TEST_VERIFY (t1 == t2); + t3 = time (NULL); + TEST_VERIFY_EXIT (t3 != (time_t) -1); + TEST_VERIFY (t3 >= t1); + /* Also verify that after sleeping, the time returned has + increased. */ + sleep (2); + t4 = time (&t5); + TEST_VERIFY_EXIT (t4 != (time_t) -1); + TEST_VERIFY (t4 == t5); + TEST_VERIFY (t4 > t3); + t6 = time (NULL); + TEST_VERIFY_EXIT (t6 != (time_t) -1); + TEST_VERIFY (t6 >= t4); + return 0; +} + +#include <support/test-driver.c>