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 (abs(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 int remain; 188 __thread int got_signal; 189 190 static void *distribution_thread(void *arg) 191 { 192 while (__atomic_load_n(&remain, __ATOMIC_RELAXED)); 193 return NULL; 194 } 195 196 static void distribution_handler(int nr) 197 { 198 if (!__atomic_exchange_n(&got_signal, 1, __ATOMIC_RELAXED)) 199 __atomic_fetch_sub(&remain, 1, __ATOMIC_RELAXED); 200 } 201 202 /* 203 * Test that all running threads _eventually_ receive CLOCK_PROCESS_CPUTIME_ID 204 * timer signals. This primarily tests that the kernel does not favour any one. 205 */ 206 static int check_timer_distribution(void) 207 { 208 int err, i; 209 timer_t id; 210 const int nthreads = 10; 211 pthread_t threads[nthreads]; 212 struct itimerspec val = { 213 .it_value.tv_sec = 0, 214 .it_value.tv_nsec = 1000 * 1000, 215 .it_interval.tv_sec = 0, 216 .it_interval.tv_nsec = 1000 * 1000, 217 }; 218 219 remain = nthreads + 1; /* worker threads + this thread */ 220 signal(SIGALRM, distribution_handler); 221 err = timer_create(CLOCK_PROCESS_CPUTIME_ID, NULL, &id); 222 if (err < 0) { 223 ksft_perror("Can't create timer"); 224 return -1; 225 } 226 err = timer_settime(id, 0, &val, NULL); 227 if (err < 0) { 228 ksft_perror("Can't set timer"); 229 return -1; 230 } 231 232 for (i = 0; i < nthreads; i++) { 233 err = pthread_create(&threads[i], NULL, distribution_thread, 234 NULL); 235 if (err) { 236 ksft_print_msg("Can't create thread: %s (%d)\n", 237 strerror(errno), errno); 238 return -1; 239 } 240 } 241 242 /* Wait for all threads to receive the signal. */ 243 while (__atomic_load_n(&remain, __ATOMIC_RELAXED)); 244 245 for (i = 0; i < nthreads; i++) { 246 err = pthread_join(threads[i], NULL); 247 if (err) { 248 ksft_print_msg("Can't join thread: %s (%d)\n", 249 strerror(errno), errno); 250 return -1; 251 } 252 } 253 254 if (timer_delete(id)) { 255 ksft_perror("Can't delete timer"); 256 return -1; 257 } 258 259 ksft_test_result_pass("check_timer_distribution\n"); 260 return 0; 261 } 262 263 int main(int argc, char **argv) 264 { 265 ksft_print_header(); 266 ksft_set_plan(6); 267 268 ksft_print_msg("Testing posix timers. False negative may happen on CPU execution \n"); 269 ksft_print_msg("based timers if other threads run on the CPU...\n"); 270 271 if (check_itimer(ITIMER_VIRTUAL) < 0) 272 return ksft_exit_fail(); 273 274 if (check_itimer(ITIMER_PROF) < 0) 275 return ksft_exit_fail(); 276 277 if (check_itimer(ITIMER_REAL) < 0) 278 return ksft_exit_fail(); 279 280 if (check_timer_create(CLOCK_THREAD_CPUTIME_ID) < 0) 281 return ksft_exit_fail(); 282 283 /* 284 * It's unfortunately hard to reliably test a timer expiration 285 * on parallel multithread cputime. We could arm it to expire 286 * on DELAY * nr_threads, with nr_threads busy looping, then wait 287 * the normal DELAY since the time is elapsing nr_threads faster. 288 * But for that we need to ensure we have real physical free CPUs 289 * to ensure true parallelism. So test only one thread until we 290 * find a better solution. 291 */ 292 if (check_timer_create(CLOCK_PROCESS_CPUTIME_ID) < 0) 293 return ksft_exit_fail(); 294 295 if (check_timer_distribution() < 0) 296 return ksft_exit_fail(); 297 298 ksft_finished(); 299 } 300