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 int err; 80 struct timeval start, end; 81 struct itimerval val = { 82 .it_value.tv_sec = DELAY, 83 }; 84 85 printf("Check itimer "); 86 87 if (which == ITIMER_VIRTUAL) 88 printf("virtual... "); 89 else if (which == ITIMER_PROF) 90 printf("prof... "); 91 else if (which == ITIMER_REAL) 92 printf("real... "); 93 94 fflush(stdout); 95 96 done = 0; 97 98 if (which == ITIMER_VIRTUAL) 99 signal(SIGVTALRM, sig_handler); 100 else if (which == ITIMER_PROF) 101 signal(SIGPROF, sig_handler); 102 else if (which == ITIMER_REAL) 103 signal(SIGALRM, sig_handler); 104 105 err = gettimeofday(&start, NULL); 106 if (err < 0) { 107 perror("Can't call gettimeofday()\n"); 108 return -1; 109 } 110 111 err = setitimer(which, &val, NULL); 112 if (err < 0) { 113 perror("Can't set timer\n"); 114 return -1; 115 } 116 117 if (which == ITIMER_VIRTUAL) 118 user_loop(); 119 else if (which == ITIMER_PROF) 120 kernel_loop(); 121 else if (which == ITIMER_REAL) 122 idle_loop(); 123 124 err = gettimeofday(&end, NULL); 125 if (err < 0) { 126 perror("Can't call gettimeofday()\n"); 127 return -1; 128 } 129 130 if (!check_diff(start, end)) 131 printf("[OK]\n"); 132 else 133 printf("[FAIL]\n"); 134 135 return 0; 136 } 137 138 static int check_timer_create(int which) 139 { 140 int err; 141 timer_t id; 142 struct timeval start, end; 143 struct itimerspec val = { 144 .it_value.tv_sec = DELAY, 145 }; 146 147 printf("Check timer_create() "); 148 if (which == CLOCK_THREAD_CPUTIME_ID) { 149 printf("per thread... "); 150 } else if (which == CLOCK_PROCESS_CPUTIME_ID) { 151 printf("per process... "); 152 } 153 fflush(stdout); 154 155 done = 0; 156 err = timer_create(which, NULL, &id); 157 if (err < 0) { 158 perror("Can't create timer\n"); 159 return -1; 160 } 161 signal(SIGALRM, sig_handler); 162 163 err = gettimeofday(&start, NULL); 164 if (err < 0) { 165 perror("Can't call gettimeofday()\n"); 166 return -1; 167 } 168 169 err = timer_settime(id, 0, &val, NULL); 170 if (err < 0) { 171 perror("Can't set timer\n"); 172 return -1; 173 } 174 175 user_loop(); 176 177 err = gettimeofday(&end, NULL); 178 if (err < 0) { 179 perror("Can't call gettimeofday()\n"); 180 return -1; 181 } 182 183 if (!check_diff(start, end)) 184 printf("[OK]\n"); 185 else 186 printf("[FAIL]\n"); 187 188 return 0; 189 } 190 191 int remain; 192 __thread int got_signal; 193 194 static void *distribution_thread(void *arg) 195 { 196 while (__atomic_load_n(&remain, __ATOMIC_RELAXED)); 197 return NULL; 198 } 199 200 static void distribution_handler(int nr) 201 { 202 if (!__atomic_exchange_n(&got_signal, 1, __ATOMIC_RELAXED)) 203 __atomic_fetch_sub(&remain, 1, __ATOMIC_RELAXED); 204 } 205 206 /* 207 * Test that all running threads _eventually_ receive CLOCK_PROCESS_CPUTIME_ID 208 * timer signals. This primarily tests that the kernel does not favour any one. 209 */ 210 static int check_timer_distribution(void) 211 { 212 int err, i; 213 timer_t id; 214 const int nthreads = 10; 215 pthread_t threads[nthreads]; 216 struct itimerspec val = { 217 .it_value.tv_sec = 0, 218 .it_value.tv_nsec = 1000 * 1000, 219 .it_interval.tv_sec = 0, 220 .it_interval.tv_nsec = 1000 * 1000, 221 }; 222 223 printf("Check timer_create() per process signal distribution... "); 224 fflush(stdout); 225 226 remain = nthreads + 1; /* worker threads + this thread */ 227 signal(SIGALRM, distribution_handler); 228 err = timer_create(CLOCK_PROCESS_CPUTIME_ID, NULL, &id); 229 if (err < 0) { 230 perror("Can't create timer\n"); 231 return -1; 232 } 233 err = timer_settime(id, 0, &val, NULL); 234 if (err < 0) { 235 perror("Can't set timer\n"); 236 return -1; 237 } 238 239 for (i = 0; i < nthreads; i++) { 240 if (pthread_create(&threads[i], NULL, distribution_thread, NULL)) { 241 perror("Can't create thread\n"); 242 return -1; 243 } 244 } 245 246 /* Wait for all threads to receive the signal. */ 247 while (__atomic_load_n(&remain, __ATOMIC_RELAXED)); 248 249 for (i = 0; i < nthreads; i++) { 250 if (pthread_join(threads[i], NULL)) { 251 perror("Can't join thread\n"); 252 return -1; 253 } 254 } 255 256 if (timer_delete(id)) { 257 perror("Can't delete timer\n"); 258 return -1; 259 } 260 261 printf("[OK]\n"); 262 return 0; 263 } 264 265 int main(int argc, char **argv) 266 { 267 printf("Testing posix timers. False negative may happen on CPU execution \n"); 268 printf("based timers if other threads run on the CPU...\n"); 269 270 if (check_itimer(ITIMER_VIRTUAL) < 0) 271 return ksft_exit_fail(); 272 273 if (check_itimer(ITIMER_PROF) < 0) 274 return ksft_exit_fail(); 275 276 if (check_itimer(ITIMER_REAL) < 0) 277 return ksft_exit_fail(); 278 279 if (check_timer_create(CLOCK_THREAD_CPUTIME_ID) < 0) 280 return ksft_exit_fail(); 281 282 /* 283 * It's unfortunately hard to reliably test a timer expiration 284 * on parallel multithread cputime. We could arm it to expire 285 * on DELAY * nr_threads, with nr_threads busy looping, then wait 286 * the normal DELAY since the time is elapsing nr_threads faster. 287 * But for that we need to ensure we have real physical free CPUs 288 * to ensure true parallelism. So test only one thread until we 289 * find a better solution. 290 */ 291 if (check_timer_create(CLOCK_PROCESS_CPUTIME_ID) < 0) 292 return ksft_exit_fail(); 293 294 if (check_timer_distribution() < 0) 295 return ksft_exit_fail(); 296 297 return ksft_exit_pass(); 298 } 299