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@xmailserver.org> 7 * Modified for inclusion in Valgrind. 8 * Copyright (C) 2008 Bart Van Assche <bvanassche@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#elif defined(__s390x__) 65#define __NR_timerfd_create 319 66#else 67#error Cannot detect your architecture! 68#endif 69#endif 70 71#ifndef __NR_timerfd_settime 72#if defined(__x86_64__) 73#define __NR_timerfd_settime 286 74#define __NR_timerfd_gettime 287 75#elif defined(__i386__) 76#define __NR_timerfd_settime 325 77#define __NR_timerfd_gettime 326 78#elif defined(__powerpc__) 79#define __NR_timerfd_settime 311 80#define __NR_timerfd_gettime 312 81#elif defined(__s390x__) 82#define __NR_timerfd_settime 320 83#define __NR_timerfd_gettime 321 84#else 85#error Cannot detect your architecture! 86#endif 87#endif 88 89 90 91/* Definitions from include/linux/timerfd.h */ 92#define TFD_TIMER_ABSTIME (1 << 0) 93 94 95 96struct tmr_type 97{ 98 int id; 99 char const *name; 100}; 101 102 103#if defined(HAVE_CLOCK_GETTIME) 104unsigned long long getustime(int clockid) 105{ 106 struct timespec tp; 107 108 if (clock_gettime((clockid_t) clockid, &tp)) 109 { 110 perror("clock_gettime"); 111 return 0; 112 } 113 114 return 1000000ULL * tp.tv_sec + tp.tv_nsec / 1000; 115} 116#else 117unsigned long long getustime(int clockid) 118{ 119 fprintf(stderr, "error: clock_gettime\n"); 120 return 0; 121} 122#endif 123 124void set_timespec(struct timespec *tmr, unsigned long long ustime) 125{ 126 tmr->tv_sec = (time_t) (ustime / 1000000ULL); 127 tmr->tv_nsec = (long) (1000ULL * (ustime % 1000000ULL)); 128} 129 130int timerfd_create(int clockid, int flags) 131{ 132 return syscall(__NR_timerfd_create, clockid, flags); 133} 134 135int timerfd_settime(int ufc, int flags, const struct itimerspec *utmr, 136 struct itimerspec *otmr) 137{ 138 return syscall(__NR_timerfd_settime, ufc, flags, utmr, otmr); 139} 140 141int timerfd_gettime(int ufc, struct itimerspec *otmr) 142{ 143 return syscall(__NR_timerfd_gettime, ufc, otmr); 144} 145 146long waittmr(int tfd, int timeo) 147{ 148 u_int64_t ticks; 149 struct pollfd pfd; 150 151 pfd.fd = tfd; 152 pfd.events = POLLIN; 153 pfd.revents = 0; 154 if (poll(&pfd, 1, timeo) < 0) 155 { 156 perror("poll"); 157 return -1; 158 } 159 if ((pfd.revents & POLLIN) == 0) 160 { 161 fprintf(stderr, "no ticks happened\n"); 162 return -1; 163 } 164 if (read(tfd, &ticks, sizeof(ticks)) != sizeof(ticks)) 165 { 166 perror("timerfd read"); 167 return -1; 168 } 169 170 return ticks; 171} 172 173int main(int ac, char **av) 174{ 175 int i, tfd; 176 long ticks; 177 unsigned long long tnow, ttmr; 178 u_int64_t uticks; 179 struct itimerspec tmr; 180 struct tmr_type clks[] = 181 { 182#if defined(HAVE_CLOCK_MONOTONIC) 183 { CLOCK_MONOTONIC, "CLOCK MONOTONIC" }, 184#endif 185 { CLOCK_REALTIME, "CLOCK REALTIME" }, 186 }; 187 188 for (i = 0; i < sizeof(clks) / sizeof(clks[0]); i++) 189 { 190 fprintf(stderr, "\n\n---------------------------------------\n"); 191 fprintf(stderr, "| testing %s\n", clks[i].name); 192 fprintf(stderr, "---------------------------------------\n\n"); 193 194 fprintf(stderr, "relative timer test (at 500 ms) ...\n"); 195 set_timespec(&tmr.it_value, 500 * 1000); 196 set_timespec(&tmr.it_interval, 0); 197 tnow = getustime(clks[i].id); 198 if ((tfd = timerfd_create(clks[i].id, 0)) == -1) 199 { 200 perror("timerfd_create"); 201 return 1; 202 } 203 204 if (timerfd_settime(tfd, 0, &tmr, NULL)) 205 { 206 perror("timerfd_settime"); 207 return 1; 208 } 209 210 fprintf(stderr, "waiting timer ...\n"); 211 ticks = waittmr(tfd, -1); 212 ttmr = getustime(clks[i].id); 213 if (ticks <= 0) 214 fprintf(stderr, "whooops! no timer showed up!\n"); 215 else 216 fprintf(stderr, "got timer ticks (%ld) after %.1f s\n", 217 ticks, (ttmr - tnow) * 1e-6); 218 219 220 fprintf(stderr, "absolute timer test (at 500 ms) ...\n"); 221 tnow = getustime(clks[i].id); 222 set_timespec(&tmr.it_value, tnow + 500 * 1000); 223 set_timespec(&tmr.it_interval, 0); 224 if (timerfd_settime(tfd, TFD_TIMER_ABSTIME, &tmr, NULL)) 225 { 226 perror("timerfd_settime"); 227 return 1; 228 } 229 230 fprintf(stderr, "waiting timer ...\n"); 231 ticks = waittmr(tfd, -1); 232 ttmr = getustime(clks[i].id); 233 if (ticks <= 0) 234 fprintf(stderr, "whooops! no timer showed up!\n"); 235 else 236 fprintf(stderr, "got timer ticks (%ld) after %.1f s\n", 237 ticks, (ttmr - tnow) * 1e-6); 238 239 fprintf(stderr, "sequential timer test (100 ms clock) ...\n"); 240 tnow = getustime(clks[i].id); 241 set_timespec(&tmr.it_value, tnow + 100 * 1000); 242 set_timespec(&tmr.it_interval, 100 * 1000); 243 if (timerfd_settime(tfd, TFD_TIMER_ABSTIME, &tmr, NULL)) 244 { 245 perror("timerfd_settime"); 246 return 1; 247 } 248 249 fprintf(stderr, "sleeping one second ...\n"); 250 sleep(1); 251 if (timerfd_gettime(tfd, &tmr)) 252 { 253 perror("timerfd_gettime"); 254 return 1; 255 } 256 fprintf(stderr, "timerfd_gettime returned:\n" 257 "\tit_value = %.1f it_interval = %.1f\n", 258 tmr.it_value.tv_sec + 1e-9 * tmr.it_value.tv_nsec, 259 tmr.it_interval.tv_sec + 1e-9 * tmr.it_interval.tv_nsec); 260 fprintf(stderr, "sleeping 1 second ...\n"); 261 sleep(1); 262 263 fprintf(stderr, "waiting timer ...\n"); 264 ticks = waittmr(tfd, -1); 265 ttmr = getustime(clks[i].id); 266 if (ticks <= 0) 267 fprintf(stderr, "whooops! no timer showed up!\n"); 268 else 269 { 270 const double delta = (ttmr - tnow) * 1e-6; 271 if (19 <= ticks && ticks <= 55 && 1.9 < delta && delta < 5.5) 272 fprintf(stderr, "got about 20 timer ticks after about 2s\n"); 273 else 274 fprintf(stderr, "got timer ticks (%ld) after %.2f s\n", ticks, delta); 275 } 276 277 278 fprintf(stderr, "O_NONBLOCK test ...\n"); 279 tnow = getustime(clks[i].id); 280 set_timespec(&tmr.it_value, 100 * 1000); 281 set_timespec(&tmr.it_interval, 0); 282 if (timerfd_settime(tfd, 0, &tmr, NULL)) 283 { 284 perror("timerfd_settime"); 285 return 1; 286 } 287#if 0 288 fprintf(stderr, "timerfd = %d\n", tfd); 289#endif 290 291 fprintf(stderr, "waiting timer (flush the single tick) ...\n"); 292 ticks = waittmr(tfd, -1); 293 ttmr = getustime(clks[i].id); 294 if (ticks <= 0) 295 fprintf(stderr, "whooops! no timer showed up!\n"); 296 else 297 fprintf(stderr, "got timer ticks (%ld) after %.1f s\n", 298 ticks, (ttmr - tnow) * 1e-6); 299 300 fcntl(tfd, F_SETFL, fcntl(tfd, F_GETFL, 0) | O_NONBLOCK); 301 302 if (read(tfd, &uticks, sizeof(uticks)) > 0) 303 fprintf(stderr, "whooops! timer ticks not zero when should have been\n"); 304 else if (errno != EAGAIN) 305 fprintf(stderr, "whooops! bad errno value (%d = '%s')!\n", 306 errno, strerror(errno)); 307 else 308 fprintf(stderr, "success\n"); 309 310 fcntl(tfd, F_SETFL, fcntl(tfd, F_GETFL, 0) & ~O_NONBLOCK); 311 312 close(tfd); 313 } 314 315 return 0; 316} 317