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 23static volatile int done; 24 25/* Busy loop in userspace to elapse ITIMER_VIRTUAL */ 26static 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 */ 35static void kernel_loop(void) 36{ 37 void *addr = sbrk(0); 38 int err = 0; 39 40 while (!done && !err) { 41 err = brk(addr + 4096); 42 err |= brk(addr); 43 } 44} 45 46/* 47 * Sleep until ITIMER_REAL expiration. 48 */ 49static void idle_loop(void) 50{ 51 pause(); 52} 53 54static void sig_handler(int nr) 55{ 56 done = 1; 57} 58 59/* 60 * Check the expected timer expiration matches the GTOD elapsed delta since 61 * we armed the timer. Keep a 0.5 sec error margin due to various jitter. 62 */ 63static int check_diff(struct timeval start, struct timeval end) 64{ 65 long long diff; 66 67 diff = end.tv_usec - start.tv_usec; 68 diff += (end.tv_sec - start.tv_sec) * USECS_PER_SEC; 69 70 if (abs(diff - DELAY * USECS_PER_SEC) > USECS_PER_SEC / 2) { 71 printf("Diff too high: %lld..", diff); 72 return -1; 73 } 74 75 return 0; 76} 77 78static int check_itimer(int which) 79{ 80 int err; 81 struct timeval start, end; 82 struct itimerval val = { 83 .it_value.tv_sec = DELAY, 84 }; 85 86 printf("Check itimer "); 87 88 if (which == ITIMER_VIRTUAL) 89 printf("virtual... "); 90 else if (which == ITIMER_PROF) 91 printf("prof... "); 92 else if (which == ITIMER_REAL) 93 printf("real... "); 94 95 fflush(stdout); 96 97 done = 0; 98 99 if (which == ITIMER_VIRTUAL) 100 signal(SIGVTALRM, sig_handler); 101 else if (which == ITIMER_PROF) 102 signal(SIGPROF, sig_handler); 103 else if (which == ITIMER_REAL) 104 signal(SIGALRM, sig_handler); 105 106 err = gettimeofday(&start, NULL); 107 if (err < 0) { 108 perror("Can't call gettimeofday()\n"); 109 return -1; 110 } 111 112 err = setitimer(which, &val, NULL); 113 if (err < 0) { 114 perror("Can't set timer\n"); 115 return -1; 116 } 117 118 if (which == ITIMER_VIRTUAL) 119 user_loop(); 120 else if (which == ITIMER_PROF) 121 kernel_loop(); 122 else if (which == ITIMER_REAL) 123 idle_loop(); 124 125 gettimeofday(&end, NULL); 126 if (err < 0) { 127 perror("Can't call gettimeofday()\n"); 128 return -1; 129 } 130 131 if (!check_diff(start, end)) 132 printf("[OK]\n"); 133 else 134 printf("[FAIL]\n"); 135 136 return 0; 137} 138 139static int check_timer_create(int which) 140{ 141 int err; 142 timer_t id; 143 struct timeval start, end; 144 struct itimerspec val = { 145 .it_value.tv_sec = DELAY, 146 }; 147 148 printf("Check timer_create() "); 149 if (which == CLOCK_THREAD_CPUTIME_ID) { 150 printf("per thread... "); 151 } else if (which == CLOCK_PROCESS_CPUTIME_ID) { 152 printf("per process... "); 153 } 154 fflush(stdout); 155 156 done = 0; 157 err = timer_create(which, NULL, &id); 158 if (err < 0) { 159 perror("Can't create timer\n"); 160 return -1; 161 } 162 signal(SIGALRM, sig_handler); 163 164 err = gettimeofday(&start, NULL); 165 if (err < 0) { 166 perror("Can't call gettimeofday()\n"); 167 return -1; 168 } 169 170 err = timer_settime(id, 0, &val, NULL); 171 if (err < 0) { 172 perror("Can't set timer\n"); 173 return -1; 174 } 175 176 user_loop(); 177 178 gettimeofday(&end, NULL); 179 if (err < 0) { 180 perror("Can't call gettimeofday()\n"); 181 return -1; 182 } 183 184 if (!check_diff(start, end)) 185 printf("[OK]\n"); 186 else 187 printf("[FAIL]\n"); 188 189 return 0; 190} 191 192int main(int argc, char **argv) 193{ 194 printf("Testing posix timers. False negative may happen on CPU execution \n"); 195 printf("based timers if other threads run on the CPU...\n"); 196 197 if (check_itimer(ITIMER_VIRTUAL) < 0) 198 return ksft_exit_fail(); 199 200 if (check_itimer(ITIMER_PROF) < 0) 201 return ksft_exit_fail(); 202 203 if (check_itimer(ITIMER_REAL) < 0) 204 return ksft_exit_fail(); 205 206 if (check_timer_create(CLOCK_THREAD_CPUTIME_ID) < 0) 207 return ksft_exit_fail(); 208 209 /* 210 * It's unfortunately hard to reliably test a timer expiration 211 * on parallel multithread cputime. We could arm it to expire 212 * on DELAY * nr_threads, with nr_threads busy looping, then wait 213 * the normal DELAY since the time is elapsing nr_threads faster. 214 * But for that we need to ensure we have real physical free CPUs 215 * to ensure true parallelism. So test only one thread until we 216 * find a better solution. 217 */ 218 if (check_timer_create(CLOCK_PROCESS_CPUTIME_ID) < 0) 219 return ksft_exit_fail(); 220 221 return ksft_exit_pass(); 222} 223