1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) 2013 Red Hat, Inc., Frederic Weisbecker <fweisbec@redhat.com>
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Selftests for a few posix timers interface.
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Kernel loop code stolen from Steven Rostedt <srostedt@redhat.com>
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <sys/time.h>
11*4882a593Smuzhiyun #include <stdio.h>
12*4882a593Smuzhiyun #include <signal.h>
13*4882a593Smuzhiyun #include <unistd.h>
14*4882a593Smuzhiyun #include <time.h>
15*4882a593Smuzhiyun #include <pthread.h>
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #include "../kselftest.h"
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #define DELAY 2
20*4882a593Smuzhiyun #define USECS_PER_SEC 1000000
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun static volatile int done;
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun /* Busy loop in userspace to elapse ITIMER_VIRTUAL */
user_loop(void)25*4882a593Smuzhiyun static void user_loop(void)
26*4882a593Smuzhiyun {
27*4882a593Smuzhiyun while (!done);
28*4882a593Smuzhiyun }
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun /*
31*4882a593Smuzhiyun * Try to spend as much time as possible in kernelspace
32*4882a593Smuzhiyun * to elapse ITIMER_PROF.
33*4882a593Smuzhiyun */
kernel_loop(void)34*4882a593Smuzhiyun static void kernel_loop(void)
35*4882a593Smuzhiyun {
36*4882a593Smuzhiyun void *addr = sbrk(0);
37*4882a593Smuzhiyun int err = 0;
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun while (!done && !err) {
40*4882a593Smuzhiyun err = brk(addr + 4096);
41*4882a593Smuzhiyun err |= brk(addr);
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun /*
46*4882a593Smuzhiyun * Sleep until ITIMER_REAL expiration.
47*4882a593Smuzhiyun */
idle_loop(void)48*4882a593Smuzhiyun static void idle_loop(void)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun pause();
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun
sig_handler(int nr)53*4882a593Smuzhiyun static void sig_handler(int nr)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun done = 1;
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun /*
59*4882a593Smuzhiyun * Check the expected timer expiration matches the GTOD elapsed delta since
60*4882a593Smuzhiyun * we armed the timer. Keep a 0.5 sec error margin due to various jitter.
61*4882a593Smuzhiyun */
check_diff(struct timeval start,struct timeval end)62*4882a593Smuzhiyun static int check_diff(struct timeval start, struct timeval end)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun long long diff;
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun diff = end.tv_usec - start.tv_usec;
67*4882a593Smuzhiyun diff += (end.tv_sec - start.tv_sec) * USECS_PER_SEC;
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun if (abs(diff - DELAY * USECS_PER_SEC) > USECS_PER_SEC / 2) {
70*4882a593Smuzhiyun printf("Diff too high: %lld..", diff);
71*4882a593Smuzhiyun return -1;
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun return 0;
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun
check_itimer(int which)77*4882a593Smuzhiyun static int check_itimer(int which)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun int err;
80*4882a593Smuzhiyun struct timeval start, end;
81*4882a593Smuzhiyun struct itimerval val = {
82*4882a593Smuzhiyun .it_value.tv_sec = DELAY,
83*4882a593Smuzhiyun };
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun printf("Check itimer ");
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun if (which == ITIMER_VIRTUAL)
88*4882a593Smuzhiyun printf("virtual... ");
89*4882a593Smuzhiyun else if (which == ITIMER_PROF)
90*4882a593Smuzhiyun printf("prof... ");
91*4882a593Smuzhiyun else if (which == ITIMER_REAL)
92*4882a593Smuzhiyun printf("real... ");
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun fflush(stdout);
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun done = 0;
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun if (which == ITIMER_VIRTUAL)
99*4882a593Smuzhiyun signal(SIGVTALRM, sig_handler);
100*4882a593Smuzhiyun else if (which == ITIMER_PROF)
101*4882a593Smuzhiyun signal(SIGPROF, sig_handler);
102*4882a593Smuzhiyun else if (which == ITIMER_REAL)
103*4882a593Smuzhiyun signal(SIGALRM, sig_handler);
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun err = gettimeofday(&start, NULL);
106*4882a593Smuzhiyun if (err < 0) {
107*4882a593Smuzhiyun perror("Can't call gettimeofday()\n");
108*4882a593Smuzhiyun return -1;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun err = setitimer(which, &val, NULL);
112*4882a593Smuzhiyun if (err < 0) {
113*4882a593Smuzhiyun perror("Can't set timer\n");
114*4882a593Smuzhiyun return -1;
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun if (which == ITIMER_VIRTUAL)
118*4882a593Smuzhiyun user_loop();
119*4882a593Smuzhiyun else if (which == ITIMER_PROF)
120*4882a593Smuzhiyun kernel_loop();
121*4882a593Smuzhiyun else if (which == ITIMER_REAL)
122*4882a593Smuzhiyun idle_loop();
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun err = gettimeofday(&end, NULL);
125*4882a593Smuzhiyun if (err < 0) {
126*4882a593Smuzhiyun perror("Can't call gettimeofday()\n");
127*4882a593Smuzhiyun return -1;
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun if (!check_diff(start, end))
131*4882a593Smuzhiyun printf("[OK]\n");
132*4882a593Smuzhiyun else
133*4882a593Smuzhiyun printf("[FAIL]\n");
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun return 0;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
check_timer_create(int which)138*4882a593Smuzhiyun static int check_timer_create(int which)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun int err;
141*4882a593Smuzhiyun timer_t id;
142*4882a593Smuzhiyun struct timeval start, end;
143*4882a593Smuzhiyun struct itimerspec val = {
144*4882a593Smuzhiyun .it_value.tv_sec = DELAY,
145*4882a593Smuzhiyun };
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun printf("Check timer_create() ");
148*4882a593Smuzhiyun if (which == CLOCK_THREAD_CPUTIME_ID) {
149*4882a593Smuzhiyun printf("per thread... ");
150*4882a593Smuzhiyun } else if (which == CLOCK_PROCESS_CPUTIME_ID) {
151*4882a593Smuzhiyun printf("per process... ");
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun fflush(stdout);
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun done = 0;
156*4882a593Smuzhiyun err = timer_create(which, NULL, &id);
157*4882a593Smuzhiyun if (err < 0) {
158*4882a593Smuzhiyun perror("Can't create timer\n");
159*4882a593Smuzhiyun return -1;
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun signal(SIGALRM, sig_handler);
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun err = gettimeofday(&start, NULL);
164*4882a593Smuzhiyun if (err < 0) {
165*4882a593Smuzhiyun perror("Can't call gettimeofday()\n");
166*4882a593Smuzhiyun return -1;
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun err = timer_settime(id, 0, &val, NULL);
170*4882a593Smuzhiyun if (err < 0) {
171*4882a593Smuzhiyun perror("Can't set timer\n");
172*4882a593Smuzhiyun return -1;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun user_loop();
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun err = gettimeofday(&end, NULL);
178*4882a593Smuzhiyun if (err < 0) {
179*4882a593Smuzhiyun perror("Can't call gettimeofday()\n");
180*4882a593Smuzhiyun return -1;
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun if (!check_diff(start, end))
184*4882a593Smuzhiyun printf("[OK]\n");
185*4882a593Smuzhiyun else
186*4882a593Smuzhiyun printf("[FAIL]\n");
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun return 0;
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun
main(int argc,char ** argv)191*4882a593Smuzhiyun int main(int argc, char **argv)
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun printf("Testing posix timers. False negative may happen on CPU execution \n");
194*4882a593Smuzhiyun printf("based timers if other threads run on the CPU...\n");
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun if (check_itimer(ITIMER_VIRTUAL) < 0)
197*4882a593Smuzhiyun return ksft_exit_fail();
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun if (check_itimer(ITIMER_PROF) < 0)
200*4882a593Smuzhiyun return ksft_exit_fail();
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun if (check_itimer(ITIMER_REAL) < 0)
203*4882a593Smuzhiyun return ksft_exit_fail();
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun if (check_timer_create(CLOCK_THREAD_CPUTIME_ID) < 0)
206*4882a593Smuzhiyun return ksft_exit_fail();
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun /*
209*4882a593Smuzhiyun * It's unfortunately hard to reliably test a timer expiration
210*4882a593Smuzhiyun * on parallel multithread cputime. We could arm it to expire
211*4882a593Smuzhiyun * on DELAY * nr_threads, with nr_threads busy looping, then wait
212*4882a593Smuzhiyun * the normal DELAY since the time is elapsing nr_threads faster.
213*4882a593Smuzhiyun * But for that we need to ensure we have real physical free CPUs
214*4882a593Smuzhiyun * to ensure true parallelism. So test only one thread until we
215*4882a593Smuzhiyun * find a better solution.
216*4882a593Smuzhiyun */
217*4882a593Smuzhiyun if (check_timer_create(CLOCK_PROCESS_CPUTIME_ID) < 0)
218*4882a593Smuzhiyun return ksft_exit_fail();
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun return ksft_exit_pass();
221*4882a593Smuzhiyun }
222