1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
|
/* Test for clock_nanosleep parameter checks and sleep duration.
Copyright (C) 2024-2025 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/>. */
/* This test has two primary goals - first, to validate that invalid
inputs to clock_nanosleep are caught, and second, to validate that
clock_nanosleep sleeps for at least the amount of time requested.
It is assumed that the system may sleep for an arbitrary additional
amount of time beyond the requested time. */
#include <unistd.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <support/xunistd.h>
#include <support/check.h>
#include <support/xthread.h>
#include <support/timespec.h>
/* This is 1 ms per test, we have 10 tests, so this file runs in on
the order of 0.01 seconds. */
#define TEST_NSEC 1000000
/* Nanoseconds per second. */
#define NSECMAX 1000000000L
static pthread_barrier_t barrier;
/* This function is intended to rack up both user and system time. */
static void *
chew_cpu (void *arg)
{
pthread_barrier_wait (&barrier);
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 = xopen ("/dev/null", O_WRONLY, 0);
for (int i = 0; i < 100; ++i)
for (size_t j = 0; j < sizeof buf; ++j)
buf[j] = 0xbb;
xwrite (nullfd, (char *) buf, sizeof buf);
close (nullfd);
}
return NULL;
}
static void
ptime_1 (const char *n, struct timespec t)
{
/* This is only for debugging failed test cases. */
printf ("%12s: %lld.%09lld\n", n, (long long int) t.tv_sec,
(long long int) t.tv_nsec);
}
#define ptime(t) ptime_1 (#t, t)
static void
test_interval_1 (const char *n_clock, clockid_t t_clock)
{
struct timespec me_before, me_after, quantum, me_sleep, me_slept;
long long int slept, min_slept;
/* Arbitrary to ensure our time period is sufficiently bigger than
the time step. */
TEST_VERIFY (clock_getres (t_clock, &quantum) == 0);
printf("Clock quantum: %lld ns, test time: %lld ns\n",
(long long int) quantum.tv_nsec, (long long int) TEST_NSEC);
TEST_VERIFY (quantum.tv_nsec <= TEST_NSEC / 10);
min_slept = TEST_NSEC;
me_sleep = make_timespec (0, min_slept);
printf ("test clock %s for %lld.%09lld sec relative\n",
n_clock, (long long int) me_sleep.tv_sec,
(long long int) me_sleep.tv_nsec);
TEST_COMPARE (clock_gettime (t_clock, &me_before), 0);
TEST_COMPARE (clock_nanosleep (t_clock, 0, &me_sleep, NULL), 0);
TEST_COMPARE (clock_gettime (t_clock, &me_after), 0);
me_slept = timespec_sub (me_after, me_before);
slept = support_timespec_ns (me_slept);
ptime (me_before);
ptime (me_after);
ptime (me_sleep);
ptime (me_slept);
printf ("test slept %lld nsec >= asked for %lld ?\n", slept, min_slept);
/* This is the important part - verify that the time slept is at
least as much as the time requested. */
TEST_VERIFY (slept >= min_slept);
}
static void
test_abs_1 (const char *n_clock, clockid_t t_clock)
{
struct timespec me_before, me_after, quantum, me_sleep;
/* Arbitrary to ensure our time period is sufficiently bigger than
the time step. */
TEST_VERIFY (clock_getres (t_clock, &quantum) == 0);
printf("Clock quantum: %lld ns, test time: %lld ns\n",
(long long int) quantum.tv_nsec, (long long int) TEST_NSEC);
TEST_VERIFY (quantum.tv_nsec <= TEST_NSEC / 10);
me_sleep = make_timespec (0, TEST_NSEC);
printf ("test clock %s for %lld.%09lld sec absolute\n",
n_clock, (long long int) me_sleep.tv_sec,
(long long int) me_sleep.tv_nsec);
TEST_COMPARE (clock_gettime (t_clock, &me_before), 0);
me_sleep = timespec_add (me_sleep, me_before);
TEST_COMPARE (clock_nanosleep (t_clock, TIMER_ABSTIME, &me_sleep, NULL), 0);
TEST_COMPARE (clock_gettime (t_clock, &me_after), 0);
ptime (me_before);
ptime (me_sleep);
ptime (me_after);
printf("test slept until %lld.%09lld after requested %lld.%09lld ?\n",
(long long int) me_after.tv_sec, (long long int) me_after.tv_nsec,
(long long int) me_sleep.tv_sec, (long long int) me_sleep.tv_nsec);
/* This is the important part - verify that the time slept is at
least as much as the time requested. */
TEST_TIMESPEC_EQUAL_OR_AFTER (me_after, me_sleep);
}
static void
test_invalids_1 (const char *the_clock_name, int the_clock,
const char *flags_name, int flags)
{
struct timespec me_before;
/* Note: do not use make_timespec() in case that function tries to
normalize the fields. */
printf ("%s: %s: test tv 0, 0\n", the_clock_name, flags_name);
me_before.tv_sec = 0;
me_before.tv_nsec = 0;
TEST_COMPARE (clock_nanosleep (the_clock, 0, &me_before, NULL), 0);
printf ("%s: %s: test tv -1, 0\n", the_clock_name, flags_name);
me_before.tv_sec = -1;
me_before.tv_nsec = 0;
TEST_COMPARE (clock_nanosleep (the_clock, 0, &me_before, NULL), EINVAL);
printf ("%s: %s: test tv 0, -1\n", the_clock_name, flags_name);
me_before.tv_sec = 0;
me_before.tv_nsec = -1;
TEST_COMPARE (clock_nanosleep (the_clock, 0, &me_before, NULL), EINVAL);
printf ("%s: %s: test tv -1, -1\n", the_clock_name, flags_name);
me_before.tv_sec = -1;
me_before.tv_nsec = -1;
TEST_COMPARE (clock_nanosleep (the_clock, 0, &me_before, NULL), EINVAL);
printf ("%s: %s: test tv 0, MAX\n", the_clock_name, flags_name);
me_before.tv_sec = 0;
me_before.tv_nsec = NSECMAX;
TEST_COMPARE (clock_nanosleep (the_clock, 0, &me_before, NULL), EINVAL);
}
static int
do_test (void)
{
pthread_t th;
pthread_barrier_init (&barrier, NULL, 2);
/* Test for proper error detection. */
#define test_invalids(c, f) test_invalids_1 (#c, c, #f, f)
test_invalids (CLOCK_REALTIME, 0);
#ifdef CLOCK_TAI
test_invalids (CLOCK_TAI, 0);
#endif
test_invalids (CLOCK_MONOTONIC, 0);
#ifdef CLOCK_BOOTTIME
test_invalids (CLOCK_BOOTTIME, 0);
#endif
test_invalids (CLOCK_PROCESS_CPUTIME_ID, 0);
test_invalids (CLOCK_REALTIME, TIMER_ABSTIME);
#ifdef CLOCK_TAI
test_invalids (CLOCK_TAI, TIMER_ABSTIME);
#endif
test_invalids (CLOCK_MONOTONIC, TIMER_ABSTIME);
#ifdef CLOCK_BOOTTIME
test_invalids (CLOCK_BOOTTIME, TIMER_ABSTIME);
#endif
test_invalids (CLOCK_PROCESS_CPUTIME_ID, TIMER_ABSTIME);
/* Test for various clocks "working". */
#define test_interval(c) test_interval_1 (#c, c)
test_interval (CLOCK_REALTIME);
#ifdef CLOCK_TAI
test_interval (CLOCK_TAI);
#endif
test_interval (CLOCK_MONOTONIC);
#ifdef CLOCK_BOOTTIME
test_interval (CLOCK_BOOTTIME);
#endif
th = xpthread_create (NULL, chew_cpu, NULL);
xpthread_barrier_wait (&barrier);
test_interval (CLOCK_PROCESS_CPUTIME_ID);
xpthread_cancel (th);
#define test_abs(c) test_abs_1 (#c, c)
test_abs (CLOCK_REALTIME);
#ifdef CLOCK_TAI
test_abs (CLOCK_TAI);
#endif
test_abs (CLOCK_MONOTONIC);
#ifdef CLOCK_BOOTTIME
test_abs (CLOCK_BOOTTIME);
#endif
th = xpthread_create (NULL, chew_cpu, NULL);
xpthread_barrier_wait (&barrier);
test_abs (CLOCK_PROCESS_CPUTIME_ID);
xpthread_cancel (th);
return 0;
}
#include <support/test-driver.c>
|