Loading...
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2013 Red Hat, Inc., Frederic Weisbecker <fweisbec@redhat.com>
4 *
5 * Selftests for a few posix timers interface.
6 *
7 * Kernel loop code stolen from Steven Rostedt <srostedt@redhat.com>
8 */
9#define _GNU_SOURCE
10#include <sys/time.h>
11#include <sys/types.h>
12#include <stdio.h>
13#include <signal.h>
14#include <stdint.h>
15#include <string.h>
16#include <unistd.h>
17#include <time.h>
18#include <include/vdso/time64.h>
19#include <pthread.h>
20
21#include "../kselftest.h"
22
23#define DELAY 2
24
25static void __fatal_error(const char *test, const char *name, const char *what)
26{
27 char buf[64];
28 char *ret_str = NULL;
29
30 ret_str = strerror_r(errno, buf, sizeof(buf));
31
32 if (name && strlen(name) && ret_str)
33 ksft_exit_fail_msg("%s %s %s %s\n", test, name, what, ret_str);
34 else if (ret_str)
35 ksft_exit_fail_msg("%s %s %s\n", test, what, ret_str);
36 else
37 ksft_exit_fail_msg("%s %s\n", test, what);
38
39}
40
41#define fatal_error(name, what) __fatal_error(__func__, name, what)
42
43static volatile int done;
44
45/* Busy loop in userspace to elapse ITIMER_VIRTUAL */
46static void user_loop(void)
47{
48 while (!done);
49}
50
51/*
52 * Try to spend as much time as possible in kernelspace
53 * to elapse ITIMER_PROF.
54 */
55static void kernel_loop(void)
56{
57 void *addr = sbrk(0);
58 int err = 0;
59
60 while (!done && !err) {
61 err = brk(addr + 4096);
62 err |= brk(addr);
63 }
64}
65
66/*
67 * Sleep until ITIMER_REAL expiration.
68 */
69static void idle_loop(void)
70{
71 pause();
72}
73
74static void sig_handler(int nr)
75{
76 done = 1;
77}
78
79/*
80 * Check the expected timer expiration matches the GTOD elapsed delta since
81 * we armed the timer. Keep a 0.5 sec error margin due to various jitter.
82 */
83static int check_diff(struct timeval start, struct timeval end)
84{
85 long long diff;
86
87 diff = end.tv_usec - start.tv_usec;
88 diff += (end.tv_sec - start.tv_sec) * USEC_PER_SEC;
89
90 if (llabs(diff - DELAY * USEC_PER_SEC) > USEC_PER_SEC / 2) {
91 printf("Diff too high: %lld..", diff);
92 return -1;
93 }
94
95 return 0;
96}
97
98static void check_itimer(int which, const char *name)
99{
100 struct timeval start, end;
101 struct itimerval val = {
102 .it_value.tv_sec = DELAY,
103 };
104
105 done = 0;
106
107 if (which == ITIMER_VIRTUAL)
108 signal(SIGVTALRM, sig_handler);
109 else if (which == ITIMER_PROF)
110 signal(SIGPROF, sig_handler);
111 else if (which == ITIMER_REAL)
112 signal(SIGALRM, sig_handler);
113
114 if (gettimeofday(&start, NULL) < 0)
115 fatal_error(name, "gettimeofday()");
116
117 if (setitimer(which, &val, NULL) < 0)
118 fatal_error(name, "setitimer()");
119
120 if (which == ITIMER_VIRTUAL)
121 user_loop();
122 else if (which == ITIMER_PROF)
123 kernel_loop();
124 else if (which == ITIMER_REAL)
125 idle_loop();
126
127 if (gettimeofday(&end, NULL) < 0)
128 fatal_error(name, "gettimeofday()");
129
130 ksft_test_result(check_diff(start, end) == 0, "%s\n", name);
131}
132
133static void check_timer_create(int which, const char *name)
134{
135 struct timeval start, end;
136 struct itimerspec val = {
137 .it_value.tv_sec = DELAY,
138 };
139 timer_t id;
140
141 done = 0;
142
143 if (timer_create(which, NULL, &id) < 0)
144 fatal_error(name, "timer_create()");
145
146 if (signal(SIGALRM, sig_handler) == SIG_ERR)
147 fatal_error(name, "signal()");
148
149 if (gettimeofday(&start, NULL) < 0)
150 fatal_error(name, "gettimeofday()");
151
152 if (timer_settime(id, 0, &val, NULL) < 0)
153 fatal_error(name, "timer_settime()");
154
155 user_loop();
156
157 if (gettimeofday(&end, NULL) < 0)
158 fatal_error(name, "gettimeofday()");
159
160 ksft_test_result(check_diff(start, end) == 0,
161 "timer_create() per %s\n", name);
162}
163
164static pthread_t ctd_thread;
165static volatile int ctd_count, ctd_failed;
166
167static void ctd_sighandler(int sig)
168{
169 if (pthread_self() != ctd_thread)
170 ctd_failed = 1;
171 ctd_count--;
172}
173
174static void *ctd_thread_func(void *arg)
175{
176 struct itimerspec val = {
177 .it_value.tv_sec = 0,
178 .it_value.tv_nsec = 1000 * 1000,
179 .it_interval.tv_sec = 0,
180 .it_interval.tv_nsec = 1000 * 1000,
181 };
182 timer_t id;
183
184 /* 1/10 seconds to ensure the leader sleeps */
185 usleep(10000);
186
187 ctd_count = 100;
188 if (timer_create(CLOCK_PROCESS_CPUTIME_ID, NULL, &id))
189 fatal_error(NULL, "timer_create()");
190 if (timer_settime(id, 0, &val, NULL))
191 fatal_error(NULL, "timer_settime()");
192 while (ctd_count > 0 && !ctd_failed)
193 ;
194
195 if (timer_delete(id))
196 fatal_error(NULL, "timer_delete()");
197
198 return NULL;
199}
200
201/*
202 * Test that only the running thread receives the timer signal.
203 */
204static void check_timer_distribution(void)
205{
206 if (signal(SIGALRM, ctd_sighandler) == SIG_ERR)
207 fatal_error(NULL, "signal()");
208
209 if (pthread_create(&ctd_thread, NULL, ctd_thread_func, NULL))
210 fatal_error(NULL, "pthread_create()");
211
212 if (pthread_join(ctd_thread, NULL))
213 fatal_error(NULL, "pthread_join()");
214
215 if (!ctd_failed)
216 ksft_test_result_pass("check signal distribution\n");
217 else if (ksft_min_kernel_version(6, 3))
218 ksft_test_result_fail("check signal distribution\n");
219 else
220 ksft_test_result_skip("check signal distribution (old kernel)\n");
221}
222
223struct tmrsig {
224 int signals;
225 int overruns;
226};
227
228static void siginfo_handler(int sig, siginfo_t *si, void *uc)
229{
230 struct tmrsig *tsig = si ? si->si_ptr : NULL;
231
232 if (tsig) {
233 tsig->signals++;
234 tsig->overruns += si->si_overrun;
235 }
236}
237
238static void *ignore_thread(void *arg)
239{
240 unsigned int *tid = arg;
241 sigset_t set;
242
243 sigemptyset(&set);
244 sigaddset(&set, SIGUSR1);
245 if (sigprocmask(SIG_BLOCK, &set, NULL))
246 fatal_error(NULL, "sigprocmask(SIG_BLOCK)");
247
248 *tid = gettid();
249 sleep(100);
250
251 if (sigprocmask(SIG_UNBLOCK, &set, NULL))
252 fatal_error(NULL, "sigprocmask(SIG_UNBLOCK)");
253 return NULL;
254}
255
256static void check_sig_ign(int thread)
257{
258 struct tmrsig tsig = { };
259 struct itimerspec its;
260 unsigned int tid = 0;
261 struct sigaction sa;
262 struct sigevent sev;
263 pthread_t pthread;
264 timer_t timerid;
265 sigset_t set;
266
267 if (thread) {
268 if (pthread_create(&pthread, NULL, ignore_thread, &tid))
269 fatal_error(NULL, "pthread_create()");
270 sleep(1);
271 }
272
273 sa.sa_flags = SA_SIGINFO;
274 sa.sa_sigaction = siginfo_handler;
275 sigemptyset(&sa.sa_mask);
276 if (sigaction(SIGUSR1, &sa, NULL))
277 fatal_error(NULL, "sigaction()");
278
279 /* Block the signal */
280 sigemptyset(&set);
281 sigaddset(&set, SIGUSR1);
282 if (sigprocmask(SIG_BLOCK, &set, NULL))
283 fatal_error(NULL, "sigprocmask(SIG_BLOCK)");
284
285 memset(&sev, 0, sizeof(sev));
286 sev.sigev_notify = SIGEV_SIGNAL;
287 sev.sigev_signo = SIGUSR1;
288 sev.sigev_value.sival_ptr = &tsig;
289 if (thread) {
290 sev.sigev_notify = SIGEV_THREAD_ID;
291 sev._sigev_un._tid = tid;
292 }
293
294 if (timer_create(CLOCK_MONOTONIC, &sev, &timerid))
295 fatal_error(NULL, "timer_create()");
296
297 /* Start the timer to expire in 100ms and 100ms intervals */
298 its.it_value.tv_sec = 0;
299 its.it_value.tv_nsec = 100000000;
300 its.it_interval.tv_sec = 0;
301 its.it_interval.tv_nsec = 100000000;
302 timer_settime(timerid, 0, &its, NULL);
303
304 sleep(1);
305
306 /* Set the signal to be ignored */
307 if (signal(SIGUSR1, SIG_IGN) == SIG_ERR)
308 fatal_error(NULL, "signal(SIG_IGN)");
309
310 sleep(1);
311
312 if (thread) {
313 /* Stop the thread first. No signal should be delivered to it */
314 if (pthread_cancel(pthread))
315 fatal_error(NULL, "pthread_cancel()");
316 if (pthread_join(pthread, NULL))
317 fatal_error(NULL, "pthread_join()");
318 }
319
320 /* Restore the handler */
321 if (sigaction(SIGUSR1, &sa, NULL))
322 fatal_error(NULL, "sigaction()");
323
324 sleep(1);
325
326 /* Unblock it, which should deliver the signal in the !thread case*/
327 if (sigprocmask(SIG_UNBLOCK, &set, NULL))
328 fatal_error(NULL, "sigprocmask(SIG_UNBLOCK)");
329
330 if (timer_delete(timerid))
331 fatal_error(NULL, "timer_delete()");
332
333 if (!thread) {
334 ksft_test_result(tsig.signals == 1 && tsig.overruns == 29,
335 "check_sig_ign SIGEV_SIGNAL\n");
336 } else {
337 ksft_test_result(tsig.signals == 0 && tsig.overruns == 0,
338 "check_sig_ign SIGEV_THREAD_ID\n");
339 }
340}
341
342static void check_rearm(void)
343{
344 struct tmrsig tsig = { };
345 struct itimerspec its;
346 struct sigaction sa;
347 struct sigevent sev;
348 timer_t timerid;
349 sigset_t set;
350
351 sa.sa_flags = SA_SIGINFO;
352 sa.sa_sigaction = siginfo_handler;
353 sigemptyset(&sa.sa_mask);
354 if (sigaction(SIGUSR1, &sa, NULL))
355 fatal_error(NULL, "sigaction()");
356
357 /* Block the signal */
358 sigemptyset(&set);
359 sigaddset(&set, SIGUSR1);
360 if (sigprocmask(SIG_BLOCK, &set, NULL))
361 fatal_error(NULL, "sigprocmask(SIG_BLOCK)");
362
363 memset(&sev, 0, sizeof(sev));
364 sev.sigev_notify = SIGEV_SIGNAL;
365 sev.sigev_signo = SIGUSR1;
366 sev.sigev_value.sival_ptr = &tsig;
367 if (timer_create(CLOCK_MONOTONIC, &sev, &timerid))
368 fatal_error(NULL, "timer_create()");
369
370 /* Start the timer to expire in 100ms and 100ms intervals */
371 its.it_value.tv_sec = 0;
372 its.it_value.tv_nsec = 100000000;
373 its.it_interval.tv_sec = 0;
374 its.it_interval.tv_nsec = 100000000;
375 if (timer_settime(timerid, 0, &its, NULL))
376 fatal_error(NULL, "timer_settime()");
377
378 sleep(1);
379
380 /* Reprogram the timer to single shot */
381 its.it_value.tv_sec = 10;
382 its.it_value.tv_nsec = 0;
383 its.it_interval.tv_sec = 0;
384 its.it_interval.tv_nsec = 0;
385 if (timer_settime(timerid, 0, &its, NULL))
386 fatal_error(NULL, "timer_settime()");
387
388 /* Unblock it, which should not deliver a signal */
389 if (sigprocmask(SIG_UNBLOCK, &set, NULL))
390 fatal_error(NULL, "sigprocmask(SIG_UNBLOCK)");
391
392 if (timer_delete(timerid))
393 fatal_error(NULL, "timer_delete()");
394
395 ksft_test_result(!tsig.signals, "check_rearm\n");
396}
397
398static void check_delete(void)
399{
400 struct tmrsig tsig = { };
401 struct itimerspec its;
402 struct sigaction sa;
403 struct sigevent sev;
404 timer_t timerid;
405 sigset_t set;
406
407 sa.sa_flags = SA_SIGINFO;
408 sa.sa_sigaction = siginfo_handler;
409 sigemptyset(&sa.sa_mask);
410 if (sigaction(SIGUSR1, &sa, NULL))
411 fatal_error(NULL, "sigaction()");
412
413 /* Block the signal */
414 sigemptyset(&set);
415 sigaddset(&set, SIGUSR1);
416 if (sigprocmask(SIG_BLOCK, &set, NULL))
417 fatal_error(NULL, "sigprocmask(SIG_BLOCK)");
418
419 memset(&sev, 0, sizeof(sev));
420 sev.sigev_notify = SIGEV_SIGNAL;
421 sev.sigev_signo = SIGUSR1;
422 sev.sigev_value.sival_ptr = &tsig;
423 if (timer_create(CLOCK_MONOTONIC, &sev, &timerid))
424 fatal_error(NULL, "timer_create()");
425
426 /* Start the timer to expire in 100ms and 100ms intervals */
427 its.it_value.tv_sec = 0;
428 its.it_value.tv_nsec = 100000000;
429 its.it_interval.tv_sec = 0;
430 its.it_interval.tv_nsec = 100000000;
431 if (timer_settime(timerid, 0, &its, NULL))
432 fatal_error(NULL, "timer_settime()");
433
434 sleep(1);
435
436 if (timer_delete(timerid))
437 fatal_error(NULL, "timer_delete()");
438
439 /* Unblock it, which should not deliver a signal */
440 if (sigprocmask(SIG_UNBLOCK, &set, NULL))
441 fatal_error(NULL, "sigprocmask(SIG_UNBLOCK)");
442
443 ksft_test_result(!tsig.signals, "check_delete\n");
444}
445
446static inline int64_t calcdiff_ns(struct timespec t1, struct timespec t2)
447{
448 int64_t diff;
449
450 diff = NSEC_PER_SEC * (int64_t)((int) t1.tv_sec - (int) t2.tv_sec);
451 diff += ((int) t1.tv_nsec - (int) t2.tv_nsec);
452 return diff;
453}
454
455static void check_sigev_none(int which, const char *name)
456{
457 struct timespec start, now;
458 struct itimerspec its;
459 struct sigevent sev;
460 timer_t timerid;
461
462 memset(&sev, 0, sizeof(sev));
463 sev.sigev_notify = SIGEV_NONE;
464
465 if (timer_create(which, &sev, &timerid))
466 fatal_error(name, "timer_create()");
467
468 /* Start the timer to expire in 100ms and 100ms intervals */
469 its.it_value.tv_sec = 0;
470 its.it_value.tv_nsec = 100000000;
471 its.it_interval.tv_sec = 0;
472 its.it_interval.tv_nsec = 100000000;
473 timer_settime(timerid, 0, &its, NULL);
474
475 if (clock_gettime(which, &start))
476 fatal_error(name, "clock_gettime()");
477
478 do {
479 if (clock_gettime(which, &now))
480 fatal_error(name, "clock_gettime()");
481 } while (calcdiff_ns(now, start) < NSEC_PER_SEC);
482
483 if (timer_gettime(timerid, &its))
484 fatal_error(name, "timer_gettime()");
485
486 if (timer_delete(timerid))
487 fatal_error(name, "timer_delete()");
488
489 ksft_test_result(its.it_value.tv_sec || its.it_value.tv_nsec,
490 "check_sigev_none %s\n", name);
491}
492
493static void check_gettime(int which, const char *name)
494{
495 struct itimerspec its, prev;
496 struct timespec start, now;
497 struct sigevent sev;
498 timer_t timerid;
499 int wraps = 0;
500 sigset_t set;
501
502 /* Block the signal */
503 sigemptyset(&set);
504 sigaddset(&set, SIGUSR1);
505 if (sigprocmask(SIG_BLOCK, &set, NULL))
506 fatal_error(name, "sigprocmask(SIG_BLOCK)");
507
508 memset(&sev, 0, sizeof(sev));
509 sev.sigev_notify = SIGEV_SIGNAL;
510 sev.sigev_signo = SIGUSR1;
511
512 if (timer_create(which, &sev, &timerid))
513 fatal_error(name, "timer_create()");
514
515 /* Start the timer to expire in 100ms and 100ms intervals */
516 its.it_value.tv_sec = 0;
517 its.it_value.tv_nsec = 100000000;
518 its.it_interval.tv_sec = 0;
519 its.it_interval.tv_nsec = 100000000;
520 if (timer_settime(timerid, 0, &its, NULL))
521 fatal_error(name, "timer_settime()");
522
523 if (timer_gettime(timerid, &prev))
524 fatal_error(name, "timer_gettime()");
525
526 if (clock_gettime(which, &start))
527 fatal_error(name, "clock_gettime()");
528
529 do {
530 if (clock_gettime(which, &now))
531 fatal_error(name, "clock_gettime()");
532 if (timer_gettime(timerid, &its))
533 fatal_error(name, "timer_gettime()");
534 if (its.it_value.tv_nsec > prev.it_value.tv_nsec)
535 wraps++;
536 prev = its;
537
538 } while (calcdiff_ns(now, start) < NSEC_PER_SEC);
539
540 if (timer_delete(timerid))
541 fatal_error(name, "timer_delete()");
542
543 ksft_test_result(wraps > 1, "check_gettime %s\n", name);
544}
545
546static void check_overrun(int which, const char *name)
547{
548 struct timespec start, now;
549 struct tmrsig tsig = { };
550 struct itimerspec its;
551 struct sigaction sa;
552 struct sigevent sev;
553 timer_t timerid;
554 sigset_t set;
555
556 sa.sa_flags = SA_SIGINFO;
557 sa.sa_sigaction = siginfo_handler;
558 sigemptyset(&sa.sa_mask);
559 if (sigaction(SIGUSR1, &sa, NULL))
560 fatal_error(name, "sigaction()");
561
562 /* Block the signal */
563 sigemptyset(&set);
564 sigaddset(&set, SIGUSR1);
565 if (sigprocmask(SIG_BLOCK, &set, NULL))
566 fatal_error(name, "sigprocmask(SIG_BLOCK)");
567
568 memset(&sev, 0, sizeof(sev));
569 sev.sigev_notify = SIGEV_SIGNAL;
570 sev.sigev_signo = SIGUSR1;
571 sev.sigev_value.sival_ptr = &tsig;
572 if (timer_create(which, &sev, &timerid))
573 fatal_error(name, "timer_create()");
574
575 /* Start the timer to expire in 100ms and 100ms intervals */
576 its.it_value.tv_sec = 0;
577 its.it_value.tv_nsec = 100000000;
578 its.it_interval.tv_sec = 0;
579 its.it_interval.tv_nsec = 100000000;
580 if (timer_settime(timerid, 0, &its, NULL))
581 fatal_error(name, "timer_settime()");
582
583 if (clock_gettime(which, &start))
584 fatal_error(name, "clock_gettime()");
585
586 do {
587 if (clock_gettime(which, &now))
588 fatal_error(name, "clock_gettime()");
589 } while (calcdiff_ns(now, start) < NSEC_PER_SEC);
590
591 /* Unblock it, which should deliver a signal */
592 if (sigprocmask(SIG_UNBLOCK, &set, NULL))
593 fatal_error(name, "sigprocmask(SIG_UNBLOCK)");
594
595 if (timer_delete(timerid))
596 fatal_error(name, "timer_delete()");
597
598 ksft_test_result(tsig.signals == 1 && tsig.overruns == 9,
599 "check_overrun %s\n", name);
600}
601
602int main(int argc, char **argv)
603{
604 ksft_print_header();
605 ksft_set_plan(18);
606
607 ksft_print_msg("Testing posix timers. False negative may happen on CPU execution \n");
608 ksft_print_msg("based timers if other threads run on the CPU...\n");
609
610 check_itimer(ITIMER_VIRTUAL, "ITIMER_VIRTUAL");
611 check_itimer(ITIMER_PROF, "ITIMER_PROF");
612 check_itimer(ITIMER_REAL, "ITIMER_REAL");
613 check_timer_create(CLOCK_THREAD_CPUTIME_ID, "CLOCK_THREAD_CPUTIME_ID");
614
615 /*
616 * It's unfortunately hard to reliably test a timer expiration
617 * on parallel multithread cputime. We could arm it to expire
618 * on DELAY * nr_threads, with nr_threads busy looping, then wait
619 * the normal DELAY since the time is elapsing nr_threads faster.
620 * But for that we need to ensure we have real physical free CPUs
621 * to ensure true parallelism. So test only one thread until we
622 * find a better solution.
623 */
624 check_timer_create(CLOCK_PROCESS_CPUTIME_ID, "CLOCK_PROCESS_CPUTIME_ID");
625 check_timer_distribution();
626
627 check_sig_ign(0);
628 check_sig_ign(1);
629 check_rearm();
630 check_delete();
631 check_sigev_none(CLOCK_MONOTONIC, "CLOCK_MONOTONIC");
632 check_sigev_none(CLOCK_PROCESS_CPUTIME_ID, "CLOCK_PROCESS_CPUTIME_ID");
633 check_gettime(CLOCK_MONOTONIC, "CLOCK_MONOTONIC");
634 check_gettime(CLOCK_PROCESS_CPUTIME_ID, "CLOCK_PROCESS_CPUTIME_ID");
635 check_gettime(CLOCK_THREAD_CPUTIME_ID, "CLOCK_THREAD_CPUTIME_ID");
636 check_overrun(CLOCK_MONOTONIC, "CLOCK_MONOTONIC");
637 check_overrun(CLOCK_PROCESS_CPUTIME_ID, "CLOCK_PROCESS_CPUTIME_ID");
638 check_overrun(CLOCK_THREAD_CPUTIME_ID, "CLOCK_THREAD_CPUTIME_ID");
639
640 ksft_finished();
641}
1/*
2 * Copyright (C) 2013 Red Hat, Inc., Frederic Weisbecker <fweisbec@redhat.com>
3 *
4 * Licensed under the terms of the GNU GPL License version 2
5 *
6 * Selftests for a few posix timers interface.
7 *
8 * Kernel loop code stolen from Steven Rostedt <srostedt@redhat.com>
9 */
10
11#include <sys/time.h>
12#include <stdio.h>
13#include <signal.h>
14#include <unistd.h>
15#include <time.h>
16#include <pthread.h>
17
18#include "../kselftest.h"
19
20#define DELAY 2
21#define USECS_PER_SEC 1000000
22
23static volatile int done;
24
25/* Busy loop in userspace to elapse ITIMER_VIRTUAL */
26static void user_loop(void)
27{
28 while (!done);
29}
30
31/*
32 * Try to spend as much time as possible in kernelspace
33 * to elapse ITIMER_PROF.
34 */
35static void kernel_loop(void)
36{
37 void *addr = sbrk(0);
38 int err = 0;
39
40 while (!done && !err) {
41 err = brk(addr + 4096);
42 err |= brk(addr);
43 }
44}
45
46/*
47 * Sleep until ITIMER_REAL expiration.
48 */
49static void idle_loop(void)
50{
51 pause();
52}
53
54static void sig_handler(int nr)
55{
56 done = 1;
57}
58
59/*
60 * Check the expected timer expiration matches the GTOD elapsed delta since
61 * we armed the timer. Keep a 0.5 sec error margin due to various jitter.
62 */
63static int check_diff(struct timeval start, struct timeval end)
64{
65 long long diff;
66
67 diff = end.tv_usec - start.tv_usec;
68 diff += (end.tv_sec - start.tv_sec) * USECS_PER_SEC;
69
70 if (abs(diff - DELAY * USECS_PER_SEC) > USECS_PER_SEC / 2) {
71 printf("Diff too high: %lld..", diff);
72 return -1;
73 }
74
75 return 0;
76}
77
78static int check_itimer(int which)
79{
80 int err;
81 struct timeval start, end;
82 struct itimerval val = {
83 .it_value.tv_sec = DELAY,
84 };
85
86 printf("Check itimer ");
87
88 if (which == ITIMER_VIRTUAL)
89 printf("virtual... ");
90 else if (which == ITIMER_PROF)
91 printf("prof... ");
92 else if (which == ITIMER_REAL)
93 printf("real... ");
94
95 fflush(stdout);
96
97 done = 0;
98
99 if (which == ITIMER_VIRTUAL)
100 signal(SIGVTALRM, sig_handler);
101 else if (which == ITIMER_PROF)
102 signal(SIGPROF, sig_handler);
103 else if (which == ITIMER_REAL)
104 signal(SIGALRM, sig_handler);
105
106 err = gettimeofday(&start, NULL);
107 if (err < 0) {
108 perror("Can't call gettimeofday()\n");
109 return -1;
110 }
111
112 err = setitimer(which, &val, NULL);
113 if (err < 0) {
114 perror("Can't set timer\n");
115 return -1;
116 }
117
118 if (which == ITIMER_VIRTUAL)
119 user_loop();
120 else if (which == ITIMER_PROF)
121 kernel_loop();
122 else if (which == ITIMER_REAL)
123 idle_loop();
124
125 gettimeofday(&end, NULL);
126 if (err < 0) {
127 perror("Can't call gettimeofday()\n");
128 return -1;
129 }
130
131 if (!check_diff(start, end))
132 printf("[OK]\n");
133 else
134 printf("[FAIL]\n");
135
136 return 0;
137}
138
139static int check_timer_create(int which)
140{
141 int err;
142 timer_t id;
143 struct timeval start, end;
144 struct itimerspec val = {
145 .it_value.tv_sec = DELAY,
146 };
147
148 printf("Check timer_create() ");
149 if (which == CLOCK_THREAD_CPUTIME_ID) {
150 printf("per thread... ");
151 } else if (which == CLOCK_PROCESS_CPUTIME_ID) {
152 printf("per process... ");
153 }
154 fflush(stdout);
155
156 done = 0;
157 err = timer_create(which, NULL, &id);
158 if (err < 0) {
159 perror("Can't create timer\n");
160 return -1;
161 }
162 signal(SIGALRM, sig_handler);
163
164 err = gettimeofday(&start, NULL);
165 if (err < 0) {
166 perror("Can't call gettimeofday()\n");
167 return -1;
168 }
169
170 err = timer_settime(id, 0, &val, NULL);
171 if (err < 0) {
172 perror("Can't set timer\n");
173 return -1;
174 }
175
176 user_loop();
177
178 gettimeofday(&end, NULL);
179 if (err < 0) {
180 perror("Can't call gettimeofday()\n");
181 return -1;
182 }
183
184 if (!check_diff(start, end))
185 printf("[OK]\n");
186 else
187 printf("[FAIL]\n");
188
189 return 0;
190}
191
192int main(int argc, char **argv)
193{
194 printf("Testing posix timers. False negative may happen on CPU execution \n");
195 printf("based timers if other threads run on the CPU...\n");
196
197 if (check_itimer(ITIMER_VIRTUAL) < 0)
198 return ksft_exit_fail();
199
200 if (check_itimer(ITIMER_PROF) < 0)
201 return ksft_exit_fail();
202
203 if (check_itimer(ITIMER_REAL) < 0)
204 return ksft_exit_fail();
205
206 if (check_timer_create(CLOCK_THREAD_CPUTIME_ID) < 0)
207 return ksft_exit_fail();
208
209 /*
210 * It's unfortunately hard to reliably test a timer expiration
211 * on parallel multithread cputime. We could arm it to expire
212 * on DELAY * nr_threads, with nr_threads busy looping, then wait
213 * the normal DELAY since the time is elapsing nr_threads faster.
214 * But for that we need to ensure we have real physical free CPUs
215 * to ensure true parallelism. So test only one thread until we
216 * find a better solution.
217 */
218 if (check_timer_create(CLOCK_PROCESS_CPUTIME_ID) < 0)
219 return ksft_exit_fail();
220
221 return ksft_exit_pass();
222}