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 
23 static volatile int done;
24 
25 /* Busy loop in userspace to elapse ITIMER_VIRTUAL */
26 static 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  */
35 static 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  */
49 static void idle_loop(void)
50 {
51 	pause();
52 }
53 
54 static 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  */
63 static 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 
78 static 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 	err = 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 
139 static 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 	err = 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 
192 int 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 }
223