Home | History | Annotate | Download | only in linux
      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 #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)
    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
    117 unsigned long long getustime(int clockid)
    118 {
    119   fprintf(stderr, "error: clock_gettime\n");
    120   return 0;
    121 }
    122 #endif
    123 
    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 
    130 int timerfd_create(int clockid, int flags)
    131 {
    132   return syscall(__NR_timerfd_create, clockid, flags);
    133 }
    134 
    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 
    141 int timerfd_gettime(int ufc, struct itimerspec *otmr)
    142 {
    143   return syscall(__NR_timerfd_gettime, ufc, otmr);
    144 }
    145 
    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 
    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