~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/timers/posix_timers.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 
 10 #include <sys/time.h>
 11 #include <stdio.h>
 12 #include <signal.h>
 13 #include <unistd.h>
 14 #include <time.h>
 15 #include <pthread.h>
 16 
 17 #include "../kselftest.h"
 18 
 19 #define DELAY 2
 20 #define USECS_PER_SEC 1000000
 21 
 22 static volatile int done;
 23 
 24 /* Busy loop in userspace to elapse ITIMER_VIRTUAL */
 25 static void user_loop(void)
 26 {
 27         while (!done);
 28 }
 29 
 30 /*
 31  * Try to spend as much time as possible in kernelspace
 32  * to elapse ITIMER_PROF.
 33  */
 34 static void kernel_loop(void)
 35 {
 36         void *addr = sbrk(0);
 37         int err = 0;
 38 
 39         while (!done && !err) {
 40                 err = brk(addr + 4096);
 41                 err |= brk(addr);
 42         }
 43 }
 44 
 45 /*
 46  * Sleep until ITIMER_REAL expiration.
 47  */
 48 static void idle_loop(void)
 49 {
 50         pause();
 51 }
 52 
 53 static void sig_handler(int nr)
 54 {
 55         done = 1;
 56 }
 57 
 58 /*
 59  * Check the expected timer expiration matches the GTOD elapsed delta since
 60  * we armed the timer. Keep a 0.5 sec error margin due to various jitter.
 61  */
 62 static int check_diff(struct timeval start, struct timeval end)
 63 {
 64         long long diff;
 65 
 66         diff = end.tv_usec - start.tv_usec;
 67         diff += (end.tv_sec - start.tv_sec) * USECS_PER_SEC;
 68 
 69         if (llabs(diff - DELAY * USECS_PER_SEC) > USECS_PER_SEC / 2) {
 70                 printf("Diff too high: %lld..", diff);
 71                 return -1;
 72         }
 73 
 74         return 0;
 75 }
 76 
 77 static int check_itimer(int which)
 78 {
 79         const char *name;
 80         int err;
 81         struct timeval start, end;
 82         struct itimerval val = {
 83                 .it_value.tv_sec = DELAY,
 84         };
 85 
 86         if (which == ITIMER_VIRTUAL)
 87                 name = "ITIMER_VIRTUAL";
 88         else if (which == ITIMER_PROF)
 89                 name = "ITIMER_PROF";
 90         else if (which == ITIMER_REAL)
 91                 name = "ITIMER_REAL";
 92         else
 93                 return -1;
 94 
 95         done = 0;
 96 
 97         if (which == ITIMER_VIRTUAL)
 98                 signal(SIGVTALRM, sig_handler);
 99         else if (which == ITIMER_PROF)
100                 signal(SIGPROF, sig_handler);
101         else if (which == ITIMER_REAL)
102                 signal(SIGALRM, sig_handler);
103 
104         err = gettimeofday(&start, NULL);
105         if (err < 0) {
106                 ksft_perror("Can't call gettimeofday()");
107                 return -1;
108         }
109 
110         err = setitimer(which, &val, NULL);
111         if (err < 0) {
112                 ksft_perror("Can't set timer");
113                 return -1;
114         }
115 
116         if (which == ITIMER_VIRTUAL)
117                 user_loop();
118         else if (which == ITIMER_PROF)
119                 kernel_loop();
120         else if (which == ITIMER_REAL)
121                 idle_loop();
122 
123         err = gettimeofday(&end, NULL);
124         if (err < 0) {
125                 ksft_perror("Can't call gettimeofday()");
126                 return -1;
127         }
128 
129         ksft_test_result(check_diff(start, end) == 0, "%s\n", name);
130 
131         return 0;
132 }
133 
134 static int check_timer_create(int which)
135 {
136         const char *type;
137         int err;
138         timer_t id;
139         struct timeval start, end;
140         struct itimerspec val = {
141                 .it_value.tv_sec = DELAY,
142         };
143 
144         if (which == CLOCK_THREAD_CPUTIME_ID) {
145                 type = "thread";
146         } else if (which == CLOCK_PROCESS_CPUTIME_ID) {
147                 type = "process";
148         } else {
149                 ksft_print_msg("Unknown timer_create() type %d\n", which);
150                 return -1;
151         }
152 
153         done = 0;
154         err = timer_create(which, NULL, &id);
155         if (err < 0) {
156                 ksft_perror("Can't create timer");
157                 return -1;
158         }
159         signal(SIGALRM, sig_handler);
160 
161         err = gettimeofday(&start, NULL);
162         if (err < 0) {
163                 ksft_perror("Can't call gettimeofday()");
164                 return -1;
165         }
166 
167         err = timer_settime(id, 0, &val, NULL);
168         if (err < 0) {
169                 ksft_perror("Can't set timer");
170                 return -1;
171         }
172 
173         user_loop();
174 
175         err = gettimeofday(&end, NULL);
176         if (err < 0) {
177                 ksft_perror("Can't call gettimeofday()");
178                 return -1;
179         }
180 
181         ksft_test_result(check_diff(start, end) == 0,
182                          "timer_create() per %s\n", type);
183 
184         return 0;
185 }
186 
187 static pthread_t ctd_thread;
188 static volatile int ctd_count, ctd_failed;
189 
190 static void ctd_sighandler(int sig)
191 {
192         if (pthread_self() != ctd_thread)
193                 ctd_failed = 1;
194         ctd_count--;
195 }
196 
197 static void *ctd_thread_func(void *arg)
198 {
199         struct itimerspec val = {
200                 .it_value.tv_sec = 0,
201                 .it_value.tv_nsec = 1000 * 1000,
202                 .it_interval.tv_sec = 0,
203                 .it_interval.tv_nsec = 1000 * 1000,
204         };
205         timer_t id;
206 
207         /* 1/10 seconds to ensure the leader sleeps */
208         usleep(10000);
209 
210         ctd_count = 100;
211         if (timer_create(CLOCK_PROCESS_CPUTIME_ID, NULL, &id))
212                 return "Can't create timer\n";
213         if (timer_settime(id, 0, &val, NULL))
214                 return "Can't set timer\n";
215 
216         while (ctd_count > 0 && !ctd_failed)
217                 ;
218 
219         if (timer_delete(id))
220                 return "Can't delete timer\n";
221 
222         return NULL;
223 }
224 
225 /*
226  * Test that only the running thread receives the timer signal.
227  */
228 static int check_timer_distribution(void)
229 {
230         const char *errmsg;
231 
232         signal(SIGALRM, ctd_sighandler);
233 
234         errmsg = "Can't create thread\n";
235         if (pthread_create(&ctd_thread, NULL, ctd_thread_func, NULL))
236                 goto err;
237 
238         errmsg = "Can't join thread\n";
239         if (pthread_join(ctd_thread, (void **)&errmsg) || errmsg)
240                 goto err;
241 
242         if (!ctd_failed)
243                 ksft_test_result_pass("check signal distribution\n");
244         else if (ksft_min_kernel_version(6, 3))
245                 ksft_test_result_fail("check signal distribution\n");
246         else
247                 ksft_test_result_skip("check signal distribution (old kernel)\n");
248         return 0;
249 err:
250         ksft_print_msg("%s", errmsg);
251         return -1;
252 }
253 
254 int main(int argc, char **argv)
255 {
256         ksft_print_header();
257         ksft_set_plan(6);
258 
259         ksft_print_msg("Testing posix timers. False negative may happen on CPU execution \n");
260         ksft_print_msg("based timers if other threads run on the CPU...\n");
261 
262         if (check_itimer(ITIMER_VIRTUAL) < 0)
263                 ksft_exit_fail();
264 
265         if (check_itimer(ITIMER_PROF) < 0)
266                 ksft_exit_fail();
267 
268         if (check_itimer(ITIMER_REAL) < 0)
269                 ksft_exit_fail();
270 
271         if (check_timer_create(CLOCK_THREAD_CPUTIME_ID) < 0)
272                 ksft_exit_fail();
273 
274         /*
275          * It's unfortunately hard to reliably test a timer expiration
276          * on parallel multithread cputime. We could arm it to expire
277          * on DELAY * nr_threads, with nr_threads busy looping, then wait
278          * the normal DELAY since the time is elapsing nr_threads faster.
279          * But for that we need to ensure we have real physical free CPUs
280          * to ensure true parallelism. So test only one thread until we
281          * find a better solution.
282          */
283         if (check_timer_create(CLOCK_PROCESS_CPUTIME_ID) < 0)
284                 ksft_exit_fail();
285 
286         if (check_timer_distribution() < 0)
287                 ksft_exit_fail();
288 
289         ksft_finished();
290 }
291 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php