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
96 struct tmr_type
97 {
98 int id;
99 char const *name;
100 };
101
102
103 #if defined(HAVE_CLOCK_GETTIME)
getustime(int clockid)104 unsigned 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
getustime(int clockid)117 unsigned long long getustime(int clockid)
118 {
119 fprintf(stderr, "error: clock_gettime\n");
120 return 0;
121 }
122 #endif
123
set_timespec(struct timespec * tmr,unsigned long long ustime)124 void 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
timerfd_create(int clockid,int flags)130 int timerfd_create(int clockid, int flags)
131 {
132 return syscall(__NR_timerfd_create, clockid, flags);
133 }
134
timerfd_settime(int ufc,int flags,const struct itimerspec * utmr,struct itimerspec * otmr)135 int 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
timerfd_gettime(int ufc,struct itimerspec * otmr)141 int timerfd_gettime(int ufc, struct itimerspec *otmr)
142 {
143 return syscall(__NR_timerfd_gettime, ufc, otmr);
144 }
145
waittmr(int tfd,int timeo)146 long 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
main(int ac,char ** av)173 int 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