1 /* 2 * Copyright (C) 2013 Red Hat, Inc., Frederic Weisbecker <fweisbec@redhat.com> 3 * 4 * Licensed under the terms of the GNU GPL License version 2 5 * 6 * Selftests for a few posix timers interface. 7 * 8 * Kernel loop code stolen from Steven Rostedt <srostedt@redhat.com> 9 */ 10 11 #include <sys/time.h> 12 #include <stdio.h> 13 #include <signal.h> 14 #include <unistd.h> 15 #include <time.h> 16 #include <pthread.h> 17 18 #include "../kselftest.h" 19 20 #define DELAY 2 21 #define USECS_PER_SEC 1000000 22 23 static volatile int done; 24 25 /* Busy loop in userspace to elapse ITIMER_VIRTUAL */ 26 static void user_loop(void) 27 { 28 while (!done); 29 } 30 31 /* 32 * Try to spend as much time as possible in kernelspace 33 * to elapse ITIMER_PROF. 34 */ 35 static void kernel_loop(void) 36 { 37 void *addr = sbrk(0); 38 39 while (!done) { 40 brk(addr + 4096); 41 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 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 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 main(int argc, char **argv) 192 { 193 int err; 194 195 printf("Testing posix timers. False negative may happen on CPU execution \n"); 196 printf("based timers if other threads run on the CPU...\n"); 197 198 if (check_itimer(ITIMER_VIRTUAL) < 0) 199 return ksft_exit_fail(); 200 201 if (check_itimer(ITIMER_PROF) < 0) 202 return ksft_exit_fail(); 203 204 if (check_itimer(ITIMER_REAL) < 0) 205 return ksft_exit_fail(); 206 207 if (check_timer_create(CLOCK_THREAD_CPUTIME_ID) < 0) 208 return ksft_exit_fail(); 209 210 /* 211 * It's unfortunately hard to reliably test a timer expiration 212 * on parallel multithread cputime. We could arm it to expire 213 * on DELAY * nr_threads, with nr_threads busy looping, then wait 214 * the normal DELAY since the time is elapsing nr_threads faster. 215 * But for that we need to ensure we have real physical free CPUs 216 * to ensure true parallelism. So test only one thread until we 217 * find a better solution. 218 */ 219 if (check_timer_create(CLOCK_PROCESS_CPUTIME_ID) < 0) 220 return ksft_exit_fail(); 221 222 return ksft_exit_pass(); 223 } 224