1 /** Test Valgrind's interception of the Linux syscalls timerfd_create(), 2 * timerfd_gettime() and timerfd_settime(). 3 * 4 * This is a modified version of 5 * timerfd-test2 by Davide Libenzi (test app for timerfd) 6 * Copyright (C) 2007 Davide Libenzi <davidel (at) xmailserver.org> 7 * Modified for inclusion in Valgrind. 8 * Copyright (C) 2008 Bart Van Assche <bvanassche (at) acm.org> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23 * 24 * See also http://www.xmailserver.org/timerfd-test2.c 25 */ 26 27 #define _GNU_SOURCE 28 29 #include "../../../config.h" 30 #include <errno.h> 31 #include <fcntl.h> 32 #include <poll.h> 33 #include <signal.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <time.h> 38 #include <unistd.h> 39 #if defined(HAVE_SYS_SIGNAL_H) 40 #include <sys/signal.h> 41 #endif 42 #if defined(HAVE_SYS_SYSCALL_H) 43 #include <sys/syscall.h> 44 #endif 45 #if defined(HAVE_SYS_TIME_H) 46 #include <sys/time.h> 47 #endif 48 #if defined(HAVE_SYS_TYPES_H) 49 #include <sys/types.h> 50 #endif 51 52 53 /* 54 * timerfd_* system call numbers introduced in 2.6.23. These constants are 55 * not yet in the glibc 2.7 headers, that is why they are defined here. 56 */ 57 #ifndef __NR_timerfd_create 58 #if defined(__x86_64__) 59 #define __NR_timerfd_create 283 60 #elif defined(__i386__) 61 #define __NR_timerfd_create 322 62 #elif defined(__powerpc__) 63 #define __NR_timerfd_create 306 64 #else 65 #error Cannot detect your architecture! 66 #endif 67 #endif 68 69 #ifndef __NR_timerfd_settime 70 #if defined(__x86_64__) 71 #define __NR_timerfd_settime 286 72 #define __NR_timerfd_gettime 287 73 #elif defined(__i386__) 74 #define __NR_timerfd_settime 325 75 #define __NR_timerfd_gettime 326 76 #elif defined(__powerpc__) 77 #define __NR_timerfd_settime 311 78 #define __NR_timerfd_gettime 312 79 #else 80 #error Cannot detect your architecture! 81 #endif 82 #endif 83 84 85 86 /* Definitions from include/linux/timerfd.h */ 87 #define TFD_TIMER_ABSTIME (1 << 0) 88 89 90 91 struct tmr_type 92 { 93 int id; 94 char const *name; 95 }; 96 97 98 #if defined(HAVE_CLOCK_GETTIME) 99 unsigned long long getustime(int clockid) 100 { 101 struct timespec tp; 102 103 if (clock_gettime((clockid_t) clockid, &tp)) 104 { 105 perror("clock_gettime"); 106 return 0; 107 } 108 109 return 1000000ULL * tp.tv_sec + tp.tv_nsec / 1000; 110 } 111 #else 112 unsigned long long getustime(int clockid) 113 { 114 fprintf(stderr, "error: clock_gettime\n"); 115 return 0; 116 } 117 #endif 118 119 void set_timespec(struct timespec *tmr, unsigned long long ustime) 120 { 121 tmr->tv_sec = (time_t) (ustime / 1000000ULL); 122 tmr->tv_nsec = (long) (1000ULL * (ustime % 1000000ULL)); 123 } 124 125 int timerfd_create(int clockid, int flags) 126 { 127 return syscall(__NR_timerfd_create, clockid, flags); 128 } 129 130 int timerfd_settime(int ufc, int flags, const struct itimerspec *utmr, 131 struct itimerspec *otmr) 132 { 133 return syscall(__NR_timerfd_settime, ufc, flags, utmr, otmr); 134 } 135 136 int timerfd_gettime(int ufc, struct itimerspec *otmr) 137 { 138 return syscall(__NR_timerfd_gettime, ufc, otmr); 139 } 140 141 long waittmr(int tfd, int timeo) 142 { 143 u_int64_t ticks; 144 struct pollfd pfd; 145 146 pfd.fd = tfd; 147 pfd.events = POLLIN; 148 pfd.revents = 0; 149 if (poll(&pfd, 1, timeo) < 0) 150 { 151 perror("poll"); 152 return -1; 153 } 154 if ((pfd.revents & POLLIN) == 0) 155 { 156 fprintf(stderr, "no ticks happened\n"); 157 return -1; 158 } 159 if (read(tfd, &ticks, sizeof(ticks)) != sizeof(ticks)) 160 { 161 perror("timerfd read"); 162 return -1; 163 } 164 165 return ticks; 166 } 167 168 int main(int ac, char **av) 169 { 170 int i, tfd; 171 long ticks; 172 unsigned long long tnow, ttmr; 173 u_int64_t uticks; 174 struct itimerspec tmr; 175 struct tmr_type clks[] = 176 { 177 #if defined(HAVE_CLOCK_MONOTONIC) 178 { CLOCK_MONOTONIC, "CLOCK MONOTONIC" }, 179 #endif 180 { CLOCK_REALTIME, "CLOCK REALTIME" }, 181 }; 182 183 for (i = 0; i < sizeof(clks) / sizeof(clks[0]); i++) 184 { 185 fprintf(stderr, "\n\n---------------------------------------\n"); 186 fprintf(stderr, "| testing %s\n", clks[i].name); 187 fprintf(stderr, "---------------------------------------\n\n"); 188 189 fprintf(stderr, "relative timer test (at 500 ms) ...\n"); 190 set_timespec(&tmr.it_value, 500 * 1000); 191 set_timespec(&tmr.it_interval, 0); 192 tnow = getustime(clks[i].id); 193 if ((tfd = timerfd_create(clks[i].id, 0)) == -1) 194 { 195 perror("timerfd_create"); 196 return 1; 197 } 198 199 if (timerfd_settime(tfd, 0, &tmr, NULL)) 200 { 201 perror("timerfd_settime"); 202 return 1; 203 } 204 205 fprintf(stderr, "waiting timer ...\n"); 206 ticks = waittmr(tfd, -1); 207 ttmr = getustime(clks[i].id); 208 if (ticks <= 0) 209 fprintf(stderr, "whooops! no timer showed up!\n"); 210 else 211 fprintf(stderr, "got timer ticks (%ld) after %.1f s\n", 212 ticks, (ttmr - tnow) * 1e-6); 213 214 215 fprintf(stderr, "absolute timer test (at 500 ms) ...\n"); 216 tnow = getustime(clks[i].id); 217 set_timespec(&tmr.it_value, tnow + 500 * 1000); 218 set_timespec(&tmr.it_interval, 0); 219 if (timerfd_settime(tfd, TFD_TIMER_ABSTIME, &tmr, NULL)) 220 { 221 perror("timerfd_settime"); 222 return 1; 223 } 224 225 fprintf(stderr, "waiting timer ...\n"); 226 ticks = waittmr(tfd, -1); 227 ttmr = getustime(clks[i].id); 228 if (ticks <= 0) 229 fprintf(stderr, "whooops! no timer showed up!\n"); 230 else 231 fprintf(stderr, "got timer ticks (%ld) after %.1f s\n", 232 ticks, (ttmr - tnow) * 1e-6); 233 234 fprintf(stderr, "sequential timer test (100 ms clock) ...\n"); 235 tnow = getustime(clks[i].id); 236 set_timespec(&tmr.it_value, tnow + 100 * 1000); 237 set_timespec(&tmr.it_interval, 100 * 1000); 238 if (timerfd_settime(tfd, TFD_TIMER_ABSTIME, &tmr, NULL)) 239 { 240 perror("timerfd_settime"); 241 return 1; 242 } 243 244 fprintf(stderr, "sleeping one second ...\n"); 245 sleep(1); 246 if (timerfd_gettime(tfd, &tmr)) 247 { 248 perror("timerfd_gettime"); 249 return 1; 250 } 251 fprintf(stderr, "timerfd_gettime returned:\n" 252 "\tit_value = %.1f it_interval = %.1f\n", 253 tmr.it_value.tv_sec + 1e-9 * tmr.it_value.tv_nsec, 254 tmr.it_interval.tv_sec + 1e-9 * tmr.it_interval.tv_nsec); 255 fprintf(stderr, "sleeping 1 second ...\n"); 256 sleep(1); 257 258 fprintf(stderr, "waiting timer ...\n"); 259 ticks = waittmr(tfd, -1); 260 ttmr = getustime(clks[i].id); 261 if (ticks <= 0) 262 fprintf(stderr, "whooops! no timer showed up!\n"); 263 else 264 { 265 const double delta = (ttmr - tnow) * 1e-6; 266 if (1.9 < delta && delta < 2.1) 267 fprintf(stderr, "got timer ticks (%ld) after about 2s\n", ticks); 268 else 269 fprintf(stderr, "got timer ticks (%ld) after %.1f s\n", ticks, delta); 270 } 271 272 273 fprintf(stderr, "O_NONBLOCK test ...\n"); 274 tnow = getustime(clks[i].id); 275 set_timespec(&tmr.it_value, 100 * 1000); 276 set_timespec(&tmr.it_interval, 0); 277 if (timerfd_settime(tfd, 0, &tmr, NULL)) 278 { 279 perror("timerfd_settime"); 280 return 1; 281 } 282 #if 0 283 fprintf(stderr, "timerfd = %d\n", tfd); 284 #endif 285 286 fprintf(stderr, "waiting timer (flush the single tick) ...\n"); 287 ticks = waittmr(tfd, -1); 288 ttmr = getustime(clks[i].id); 289 if (ticks <= 0) 290 fprintf(stderr, "whooops! no timer showed up!\n"); 291 else 292 fprintf(stderr, "got timer ticks (%ld) after %.1f s\n", 293 ticks, (ttmr - tnow) * 1e-6); 294 295 fcntl(tfd, F_SETFL, fcntl(tfd, F_GETFL, 0) | O_NONBLOCK); 296 297 if (read(tfd, &uticks, sizeof(uticks)) > 0) 298 fprintf(stderr, "whooops! timer ticks not zero when should have been\n"); 299 else if (errno != EAGAIN) 300 fprintf(stderr, "whooops! bad errno value (%d = '%s')!\n", 301 errno, strerror(errno)); 302 else 303 fprintf(stderr, "success\n"); 304 305 fcntl(tfd, F_SETFL, fcntl(tfd, F_GETFL, 0) & ~O_NONBLOCK); 306 307 close(tfd); 308 } 309 310 return 0; 311 } 312