posix_timers.c (4443B)
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 22static volatile int done; 23 24/* Busy loop in userspace to elapse ITIMER_VIRTUAL */ 25static 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 */ 34static 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 */ 48static void idle_loop(void) 49{ 50 pause(); 51} 52 53static 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 */ 62static 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 77static 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 138static 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 191int main(int argc, char **argv) 192{ 193 printf("Testing posix timers. False negative may happen on CPU execution \n"); 194 printf("based timers if other threads run on the CPU...\n"); 195 196 if (check_itimer(ITIMER_VIRTUAL) < 0) 197 return ksft_exit_fail(); 198 199 if (check_itimer(ITIMER_PROF) < 0) 200 return ksft_exit_fail(); 201 202 if (check_itimer(ITIMER_REAL) < 0) 203 return ksft_exit_fail(); 204 205 if (check_timer_create(CLOCK_THREAD_CPUTIME_ID) < 0) 206 return ksft_exit_fail(); 207 208 /* 209 * It's unfortunately hard to reliably test a timer expiration 210 * on parallel multithread cputime. We could arm it to expire 211 * on DELAY * nr_threads, with nr_threads busy looping, then wait 212 * the normal DELAY since the time is elapsing nr_threads faster. 213 * But for that we need to ensure we have real physical free CPUs 214 * to ensure true parallelism. So test only one thread until we 215 * find a better solution. 216 */ 217 if (check_timer_create(CLOCK_PROCESS_CPUTIME_ID) < 0) 218 return ksft_exit_fail(); 219 220 return ksft_exit_pass(); 221}