1/* Tests for POSIX timer implementation.
2 Copyright (C) 2004-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If
17 not, see <https://www.gnu.org/licenses/>. */
18
19#include <errno.h>
20#include <signal.h>
21#include <stdio.h>
22#include <string.h>
23#include <time.h>
24#include <unistd.h>
25#include <stdint.h>
26#if _POSIX_THREADS && defined SA_SIGINFO
27# include <pthread.h>
28
29# ifndef TEST_CLOCK
30# define TEST_CLOCK CLOCK_REALTIME
31# endif
32
33pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
34pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
35
36timer_t timer_none, timer_sig1, timer_sig2, timer_thr1, timer_thr2;
37
38int thr1_cnt, thr1_err;
39union sigval thr1_sigval;
40struct timespec thr1_ts;
41
42static void
43thr1 (union sigval sigval)
44{
45 pthread_mutex_lock (mutex: &lock);
46 thr1_err = clock_gettime (TEST_CLOCK, tp: &thr1_ts);
47 if (thr1_cnt >= 5)
48 {
49 struct itimerspec it = { };
50 thr1_err |= timer_settime (timerid: timer_thr1, flags: 0, value: &it, NULL);
51 }
52 thr1_sigval = sigval;
53 ++thr1_cnt;
54 pthread_cond_signal (cond: &cond);
55 pthread_mutex_unlock (mutex: &lock);
56}
57
58int thr2_cnt, thr2_err;
59union sigval thr2_sigval;
60size_t thr2_guardsize;
61struct timespec thr2_ts;
62
63static void
64thr2 (union sigval sigval)
65{
66 pthread_attr_t nattr;
67 int err = 0;
68 size_t guardsize = -1;
69 int ret = pthread_getattr_np (th: pthread_self (), attr: &nattr);
70 if (ret)
71 {
72 errno = ret;
73 printf (format: "*** pthread_getattr_np failed: %m\n");
74 err = 1;
75 }
76 else
77 {
78 ret = pthread_attr_getguardsize (attr: &nattr, guardsize: &guardsize);
79 if (ret)
80 {
81 errno = ret;
82 printf (format: "*** pthread_attr_getguardsize failed: %m\n");
83 err = 1;
84 }
85 if (pthread_attr_destroy (attr: &nattr) != 0)
86 {
87 puts (s: "*** pthread_attr_destroy failed");
88 err = 1;
89 }
90 }
91 pthread_mutex_lock (mutex: &lock);
92 thr2_err = clock_gettime (TEST_CLOCK, tp: &thr2_ts) | err;
93 if (thr2_cnt >= 5)
94 {
95 struct itimerspec it = { };
96 thr2_err |= timer_settime (timerid: timer_thr2, flags: 0, value: &it, NULL);
97 }
98 thr2_sigval = sigval;
99 ++thr2_cnt;
100 thr2_guardsize = guardsize;
101 pthread_cond_signal (cond: &cond);
102 pthread_mutex_unlock (mutex: &lock);
103}
104
105volatile int sig1_cnt, sig1_err;
106volatile union sigval sig1_sigval;
107struct timespec sig1_ts;
108
109static void
110sig1_handler (int sig, siginfo_t *info, void *ctx)
111{
112 int err = 0;
113 if (sig != SIGRTMIN) err |= 1 << 0;
114 if (info->si_signo != SIGRTMIN) err |= 1 << 1;
115 if (info->si_code != SI_TIMER) err |= 1 << 2;
116 if (clock_gettime (TEST_CLOCK, tp: &sig1_ts) != 0)
117 err |= 1 << 3;
118 if (sig1_cnt >= 5)
119 {
120 struct itimerspec it = { };
121 if (timer_settime (timerid: timer_sig1, flags: 0, value: &it, NULL))
122 err |= 1 << 4;
123 }
124 sig1_err |= err;
125 sig1_sigval = info->si_value;
126 ++sig1_cnt;
127}
128
129volatile int sig2_cnt, sig2_err;
130volatile union sigval sig2_sigval;
131struct timespec sig2_ts;
132
133static void
134sig2_handler (int sig, siginfo_t *info, void *ctx)
135{
136 int err = 0;
137 if (sig != SIGRTMIN + 1) err |= 1 << 0;
138 if (info->si_signo != SIGRTMIN + 1) err |= 1 << 1;
139 if (info->si_code != SI_TIMER) err |= 1 << 2;
140 if (clock_gettime (TEST_CLOCK, tp: &sig2_ts) != 0)
141 err |= 1 << 3;
142 if (sig2_cnt >= 5)
143 {
144 struct itimerspec it = { };
145 if (timer_settime (timerid: timer_sig2, flags: 0, value: &it, NULL))
146 err |= 1 << 4;
147 }
148 sig2_err |= err;
149 sig2_sigval = info->si_value;
150 ++sig2_cnt;
151}
152
153/* Check if end is later or equal to start + nsec. */
154static int
155check_ts (const char *name, const struct timespec *start,
156 const struct timespec *end, long msec)
157{
158 struct timespec ts = *start;
159
160 ts.tv_sec += msec / 1000000;
161 ts.tv_nsec += (msec % 1000000) * 1000;
162 if (ts.tv_nsec >= 1000000000)
163 {
164 ++ts.tv_sec;
165 ts.tv_nsec -= 1000000000;
166 }
167 if (end->tv_sec < ts.tv_sec
168 || (end->tv_sec == ts.tv_sec && end->tv_nsec < ts.tv_nsec))
169 {
170 printf (format: "\
171*** timer %s invoked too soon: %ld.%09jd instead of expected %ld.%09jd\n",
172 name, (long) end->tv_sec, (intmax_t) end->tv_nsec,
173 (long) ts.tv_sec, (intmax_t) ts.tv_nsec);
174 return 1;
175 }
176 else
177 return 0;
178}
179
180#define TEST_FUNCTION do_test ()
181static int
182do_test (void)
183{
184 int result = 0;
185
186#ifdef TEST_CLOCK_MISSING
187 const char *missing = TEST_CLOCK_MISSING (TEST_CLOCK);
188 if (missing != NULL)
189 {
190 printf (format: "%s missing, skipping test\n", missing);
191 return 0;
192 }
193#endif
194
195 struct timespec ts;
196 if (clock_gettime (TEST_CLOCK, tp: &ts) != 0)
197 {
198 printf (format: "*** clock_gettime failed: %m\n");
199 result = 1;
200 }
201 else
202 printf (format: "clock_gettime returned timespec = { %ld, %jd }\n",
203 (long) ts.tv_sec, (intmax_t) ts.tv_nsec);
204
205 if (clock_getres (TEST_CLOCK, res: &ts) != 0)
206 {
207 printf (format: "*** clock_getres failed: %m\n");
208 result = 1;
209 }
210 else
211 printf (format: "clock_getres returned timespec = { %ld, %jd }\n",
212 (long) ts.tv_sec, (intmax_t) ts.tv_nsec);
213
214 struct sigevent ev;
215 memset (&ev, 0x11, sizeof (ev));
216 ev.sigev_notify = SIGEV_NONE;
217 if (timer_create (TEST_CLOCK, evp: &ev, timerid: &timer_none) != 0)
218 {
219 printf (format: "*** timer_create for timer_none failed: %m\n");
220 return 1;
221 }
222
223 struct sigaction sa = { .sa_sigaction = sig1_handler,
224 .sa_flags = SA_SIGINFO };
225 sigemptyset (&sa.sa_mask);
226 sigaction (SIGRTMIN, act: &sa, NULL);
227 sa.sa_sigaction = sig2_handler;
228 sigaction (SIGRTMIN + 1, act: &sa, NULL);
229
230 memset (&ev, 0x22, sizeof (ev));
231 ev.sigev_notify = SIGEV_SIGNAL;
232 ev.sigev_signo = SIGRTMIN;
233 ev.sigev_value.sival_ptr = &ev;
234 if (timer_create (TEST_CLOCK, evp: &ev, timerid: &timer_sig1) != 0)
235 {
236 printf (format: "*** timer_create for timer_sig1 failed: %m\n");
237 return 1;
238 }
239
240 memset (&ev, 0x33, sizeof (ev));
241 ev.sigev_notify = SIGEV_SIGNAL;
242 ev.sigev_signo = SIGRTMIN + 1;
243 ev.sigev_value.sival_int = 163;
244 if (timer_create (TEST_CLOCK, evp: &ev, timerid: &timer_sig2) != 0)
245 {
246 printf (format: "*** timer_create for timer_sig2 failed: %m\n");
247 return 1;
248 }
249
250 memset (&ev, 0x44, sizeof (ev));
251 ev.sigev_notify = SIGEV_THREAD;
252 ev.sigev_notify_function = thr1;
253 ev.sigev_notify_attributes = NULL;
254 ev.sigev_value.sival_ptr = &ev;
255 if (timer_create (TEST_CLOCK, evp: &ev, timerid: &timer_thr1) != 0)
256 {
257 printf (format: "*** timer_create for timer_thr1 failed: %m\n");
258 return 1;
259 }
260
261 pthread_attr_t nattr;
262 if (pthread_attr_init (attr: &nattr)
263 || pthread_attr_setguardsize (attr: &nattr, guardsize: 0))
264 {
265 puts (s: "*** pthread_attr_t setup failed");
266 result = 1;
267 }
268
269 memset (&ev, 0x55, sizeof (ev));
270 ev.sigev_notify = SIGEV_THREAD;
271 ev.sigev_notify_function = thr2;
272 ev.sigev_notify_attributes = &nattr;
273 ev.sigev_value.sival_int = 111;
274 if (timer_create (TEST_CLOCK, evp: &ev, timerid: &timer_thr2) != 0)
275 {
276 printf (format: "*** timer_create for timer_thr2 failed: %m\n");
277 return 1;
278 }
279
280 int ret = timer_getoverrun (timerid: timer_thr1);
281 if (ret != 0)
282 {
283 if (ret == -1)
284 printf (format: "*** timer_getoverrun failed: %m\n");
285 else
286 printf (format: "*** timer_getoverrun returned %d != 0\n", ret);
287 result = 1;
288 }
289
290 struct itimerspec it;
291 it.it_value.tv_sec = 0;
292 it.it_value.tv_nsec = -26;
293 it.it_interval.tv_sec = 0;
294 it.it_interval.tv_nsec = 0;
295 if (timer_settime (timerid: timer_sig1, flags: 0, value: &it, NULL) == 0)
296 {
297 puts (s: "*** timer_settime with negative tv_nsec unexpectedly succeeded");
298 result = 1;
299 }
300 else if (errno != EINVAL)
301 {
302 printf (format: "*** timer_settime with negative tv_nsec did not fail with "
303 "EINVAL: %m\n");
304 result = 1;
305 }
306
307 it.it_value.tv_nsec = 100000;
308 it.it_interval.tv_nsec = 1000000000;
309 if (timer_settime (timerid: timer_sig2, flags: 0, value: &it, NULL) == 0)
310 {
311 puts (s: "\
312*** timer_settime with tv_nsec 1000000000 unexpectedly succeeded");
313 result = 1;
314 }
315 else if (errno != EINVAL)
316 {
317 printf (format: "*** timer_settime with tv_nsec 1000000000 did not fail with "
318 "EINVAL: %m\n");
319 result = 1;
320 }
321
322#if 0
323 it.it_value.tv_nsec = 0;
324 it.it_interval.tv_nsec = -26;
325 if (timer_settime (timer_thr1, 0, &it, NULL) != 0)
326 {
327 printf ("\
328!!! timer_settime with it_value 0 it_interval invalid failed: %m\n");
329 /* FIXME: is this mandated by POSIX?
330 result = 1; */
331 }
332
333 it.it_interval.tv_nsec = 3000000000;
334 if (timer_settime (timer_thr2, 0, &it, NULL) != 0)
335 {
336 printf ("\
337!!! timer_settime with it_value 0 it_interval invalid failed: %m\n");
338 /* FIXME: is this mandated by POSIX?
339 result = 1; */
340 }
341#endif
342
343 struct timespec startts;
344 if (clock_gettime (TEST_CLOCK, tp: &startts) != 0)
345 {
346 printf (format: "*** clock_gettime failed: %m\n");
347 result = 1;
348 }
349
350 it.it_value.tv_nsec = 100000000;
351 it.it_interval.tv_nsec = 0;
352 if (timer_settime (timerid: timer_none, flags: 0, value: &it, NULL) != 0)
353 {
354 printf (format: "*** timer_settime timer_none failed: %m\n");
355 result = 1;
356 }
357
358 it.it_value.tv_nsec = 200000000;
359 if (timer_settime (timerid: timer_thr1, flags: 0, value: &it, NULL) != 0)
360 {
361 printf (format: "*** timer_settime timer_thr1 failed: %m\n");
362 result = 1;
363 }
364
365 it.it_value.tv_nsec = 300000000;
366 if (timer_settime (timerid: timer_thr2, flags: 0, value: &it, NULL) != 0)
367 {
368 printf (format: "*** timer_settime timer_thr2 failed: %m\n");
369 result = 1;
370 }
371
372 it.it_value.tv_nsec = 400000000;
373 if (timer_settime (timerid: timer_sig1, flags: 0, value: &it, NULL) != 0)
374 {
375 printf (format: "*** timer_settime timer_sig1 failed: %m\n");
376 result = 1;
377 }
378
379 it.it_value.tv_nsec = 500000000;
380 if (TEMP_FAILURE_RETRY (timer_settime (timer_sig2, 0, &it, NULL)) != 0)
381 {
382 printf (format: "*** timer_settime timer_sig2 failed: %m\n");
383 result = 1;
384 }
385
386 pthread_mutex_lock (mutex: &lock);
387 while (thr1_cnt == 0 || thr2_cnt == 0)
388 pthread_cond_wait (cond: &cond, mutex: &lock);
389 pthread_mutex_unlock (mutex: &lock);
390
391 while (sig1_cnt == 0 || sig2_cnt == 0)
392 {
393 ts.tv_sec = 0;
394 ts.tv_nsec = 100000000;
395 nanosleep (requested_time: &ts, NULL);
396 }
397
398 pthread_mutex_lock (mutex: &lock);
399
400 if (thr1_cnt != 1)
401 {
402 printf (format: "*** thr1 not called exactly once, but %d times\n", thr1_cnt);
403 result = 1;
404 }
405 else if (thr1_err)
406 {
407 puts (s: "*** an error occurred in thr1");
408 result = 1;
409 }
410 else if (thr1_sigval.sival_ptr != &ev)
411 {
412 printf (format: "*** thr1_sigval.sival_ptr %p != %p\n",
413 thr1_sigval.sival_ptr, &ev);
414 result = 1;
415 }
416 else if (check_ts (name: "thr1", start: &startts, end: &thr1_ts, msec: 200000))
417 result = 1;
418
419 if (thr2_cnt != 1)
420 {
421 printf (format: "*** thr2 not called exactly once, but %d times\n", thr2_cnt);
422 result = 1;
423 }
424 else if (thr2_err)
425 {
426 puts (s: "*** an error occurred in thr2");
427 result = 1;
428 }
429 else if (thr2_sigval.sival_int != 111)
430 {
431 printf (format: "*** thr2_sigval.sival_ptr %d != 111\n", thr2_sigval.sival_int);
432 result = 1;
433 }
434 else if (check_ts (name: "thr2", start: &startts, end: &thr2_ts, msec: 300000))
435 result = 1;
436 else if (thr2_guardsize != 0)
437 {
438 printf (format: "*** thr2 guardsize %zd != 0\n", thr2_guardsize);
439 result = 1;
440 }
441
442 pthread_mutex_unlock (mutex: &lock);
443
444 if (sig1_cnt != 1)
445 {
446 printf (format: "*** sig1 not called exactly once, but %d times\n", sig1_cnt);
447 result = 1;
448 }
449 else if (sig1_err)
450 {
451 printf (format: "*** errors occurred in sig1 handler %x\n", sig1_err);
452 result = 1;
453 }
454 else if (sig1_sigval.sival_ptr != &ev)
455 {
456 printf (format: "*** sig1_sigval.sival_ptr %p != %p\n",
457 sig1_sigval.sival_ptr, &ev);
458 result = 1;
459 }
460 else if (check_ts (name: "sig1", start: &startts, end: &sig1_ts, msec: 400000))
461 result = 1;
462
463 if (sig2_cnt != 1)
464 {
465 printf (format: "*** sig2 not called exactly once, but %d times\n", sig2_cnt);
466 result = 1;
467 }
468 else if (sig2_err)
469 {
470 printf (format: "*** errors occurred in sig2 handler %x\n", sig2_err);
471 result = 1;
472 }
473 else if (sig2_sigval.sival_int != 163)
474 {
475 printf (format: "*** sig2_sigval.sival_ptr %d != 163\n", sig2_sigval.sival_int);
476 result = 1;
477 }
478 else if (check_ts (name: "sig2", start: &startts, end: &sig2_ts, msec: 500000))
479 result = 1;
480
481 if (timer_gettime (timerid: timer_none, value: &it) != 0)
482 {
483 printf (format: "*** timer_gettime timer_none failed: %m\n");
484 result = 1;
485 }
486 else if (it.it_value.tv_sec || it.it_value.tv_nsec
487 || it.it_interval.tv_sec || it.it_interval.tv_nsec)
488 {
489 printf (format: "\
490*** timer_gettime timer_none returned { %ld.%09jd, %ld.%09jd }\n",
491 (long) it.it_value.tv_sec, (intmax_t) it.it_value.tv_nsec,
492 (long) it.it_interval.tv_sec, (intmax_t) it.it_interval.tv_nsec);
493 result = 1;
494 }
495
496 if (clock_gettime (TEST_CLOCK, tp: &startts) != 0)
497 {
498 printf (format: "*** clock_gettime failed: %m\n");
499 result = 1;
500 }
501
502 it.it_value.tv_sec = 1;
503 it.it_value.tv_nsec = 0;
504 it.it_interval.tv_sec = 0;
505 it.it_interval.tv_nsec = 100000000;
506 if (timer_settime (timerid: timer_none, flags: 0, value: &it, NULL) != 0)
507 {
508 printf (format: "*** timer_settime timer_none failed: %m\n");
509 result = 1;
510 }
511
512 it.it_value.tv_nsec = 100000000;
513 it.it_interval.tv_nsec = 200000000;
514 if (timer_settime (timerid: timer_thr1, flags: 0, value: &it, NULL) != 0)
515 {
516 printf (format: "*** timer_settime timer_thr1 failed: %m\n");
517 result = 1;
518 }
519
520 it.it_value.tv_nsec = 200000000;
521 it.it_interval.tv_nsec = 300000000;
522 if (timer_settime (timerid: timer_thr2, flags: 0, value: &it, NULL) != 0)
523 {
524 printf (format: "*** timer_settime timer_thr2 failed: %m\n");
525 result = 1;
526 }
527
528 it.it_value.tv_nsec = 300000000;
529 it.it_interval.tv_nsec = 400000000;
530 if (timer_settime (timerid: timer_sig1, flags: 0, value: &it, NULL) != 0)
531 {
532 printf (format: "*** timer_settime timer_sig1 failed: %m\n");
533 result = 1;
534 }
535
536 it.it_value.tv_nsec = 400000000;
537 it.it_interval.tv_nsec = 500000000;
538 if (TEMP_FAILURE_RETRY (timer_settime (timer_sig2, 0, &it, NULL)) != 0)
539 {
540 printf (format: "*** timer_settime timer_sig2 failed: %m\n");
541 result = 1;
542 }
543
544 pthread_mutex_lock (mutex: &lock);
545 while (thr1_cnt < 6 || thr2_cnt < 6)
546 pthread_cond_wait (cond: &cond, mutex: &lock);
547 pthread_mutex_unlock (mutex: &lock);
548
549 while (sig1_cnt < 6 || sig2_cnt < 6)
550 {
551 ts.tv_sec = 0;
552 ts.tv_nsec = 100000000;
553 nanosleep (requested_time: &ts, NULL);
554 }
555
556 pthread_mutex_lock (mutex: &lock);
557
558 if (thr1_err)
559 {
560 puts (s: "*** an error occurred in thr1");
561 result = 1;
562 }
563 else if (check_ts (name: "thr1", start: &startts, end: &thr1_ts, msec: 1100000 + 4 * 200000))
564 result = 1;
565
566 if (thr2_err)
567 {
568 puts (s: "*** an error occurred in thr2");
569 result = 1;
570 }
571 else if (check_ts (name: "thr2", start: &startts, end: &thr2_ts, msec: 1200000 + 4 * 300000))
572 result = 1;
573 else if (thr2_guardsize != 0)
574 {
575 printf (format: "*** thr2 guardsize %zd != 0\n", thr2_guardsize);
576 result = 1;
577 }
578
579 pthread_mutex_unlock (mutex: &lock);
580
581 if (sig1_err)
582 {
583 printf (format: "*** errors occurred in sig1 handler %x\n", sig1_err);
584 result = 1;
585 }
586 else if (check_ts (name: "sig1", start: &startts, end: &sig1_ts, msec: 1300000 + 4 * 400000))
587 result = 1;
588
589 if (sig2_err)
590 {
591 printf (format: "*** errors occurred in sig2 handler %x\n", sig2_err);
592 result = 1;
593 }
594 else if (check_ts (name: "sig2", start: &startts, end: &sig2_ts, msec: 1400000 + 4 * 500000))
595 result = 1;
596
597 if (timer_gettime (timerid: timer_none, value: &it) != 0)
598 {
599 printf (format: "*** timer_gettime timer_none failed: %m\n");
600 result = 1;
601 }
602 else if (it.it_interval.tv_sec || it.it_interval.tv_nsec != 100000000)
603 {
604 printf (format: "\
605!!! second timer_gettime timer_none returned it_interval %ld.%09jd\n",
606 (long) it.it_interval.tv_sec, (intmax_t) it.it_interval.tv_nsec);
607 /* FIXME: For now disabled.
608 result = 1; */
609 }
610
611 if (timer_delete (timerid: timer_none) != 0)
612 {
613 printf (format: "*** timer_delete for timer_none failed: %m\n");
614 result = 1;
615 }
616
617 if (timer_delete (timerid: timer_sig1) != 0)
618 {
619 printf (format: "*** timer_delete for timer_sig1 failed: %m\n");
620 result = 1;
621 }
622
623 if (timer_delete (timerid: timer_sig2) != 0)
624 {
625 printf (format: "*** timer_delete for timer_sig2 failed: %m\n");
626 result = 1;
627 }
628
629 if (timer_delete (timerid: timer_thr1) != 0)
630 {
631 printf (format: "*** timer_delete for timer_thr1 failed: %m\n");
632 result = 1;
633 }
634
635 if (timer_delete (timerid: timer_thr2) != 0)
636 {
637 printf (format: "*** timer_delete for timer_thr2 failed: %m\n");
638 result = 1;
639 }
640 return result;
641}
642
643#elif defined TEST_CLOCK_MISSING
644/* This just ensures that any functions called in TEST_CLOCK_MISSING
645 are not diagnosed as unused. */
646# define TEST_FUNCTION (TEST_CLOCK_MISSING (TEST_CLOCK), 0)
647#else
648# define TEST_FUNCTION 0
649#endif
650
651#include "../test-skeleton.c"
652

source code of glibc/rt/tst-timer4.c