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 return ksft_exit_fail(); 264 265 if (check_itimer(ITIMER_PROF) < 0) 266 return ksft_exit_fail(); 267 268 if (check_itimer(ITIMER_REAL) < 0) 269 return ksft_exit_fail(); 270 271 if (check_timer_create(CLOCK_THREAD_CPUTIME_ID) < 0) 272 return 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 return ksft_exit_fail(); 285 286 if (check_timer_distribution() < 0) 287 return ksft_exit_fail(); 288 289 ksft_finished(); 290 } 291