commit e5ea9aef5468404eecc8c990e6852315b7d1a0e3 Author: Joseph Myers Date: Wed Oct 30 16:48:38 2024 +0000 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. Conflicts: time/Makefile (new tests added) diff --git a/time/Makefile b/time/Makefile index ef3bb767b825f76a..b31ae723642e33bd 100644 --- a/time/Makefile +++ b/time/Makefile @@ -50,22 +50,28 @@ tests := test_time clocktest tst-posixtz tst-strptime tst_wcsftime \ tst-clock tst-clock2 tst-clock_nanosleep tst-cpuclock1 \ tst-adjtime tst-ctime tst-difftime tst-mktime4 tst-clock_settime \ tst-settimeofday tst-itimer tst-gmtime tst-timegm \ - tst-timespec_get tst-timespec_getres tst-strftime4 + tst-timespec_get tst-timespec_getres tst-strftime4 \ + tst-clock_gettime \ + tst-gettimeofday \ + tst-time \ 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 0000000000000000..5b215d11f8a0a424 --- /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 0000000000000000..51f24c0be2084a91 --- /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 + . */ + +#include +#include +#include + +#include +#include +#include + +/* 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 diff --git a/time/tst-gettimeofday-time64.c b/time/tst-gettimeofday-time64.c new file mode 100644 index 0000000000000000..6c08761ef995ce7c --- /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 0000000000000000..978ae28587d486f2 --- /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 + . */ + +#include +#include + +#include +#include + +/* 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 diff --git a/time/tst-time-time64.c b/time/tst-time-time64.c new file mode 100644 index 0000000000000000..30e8d3c86ef973cc --- /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 0000000000000000..7f24bed3530e1c1e --- /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 + . */ + +#include +#include + +#include +#include + +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