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