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