akaros/tests/timerfd.c
<<
>>
Prefs
   1/*
   2 *  timerfd() test by Davide Libenzi (test app for timerfd)
   3 *  Copyright (C) 2007  Davide Libenzi
   4 *
   5 *  This program is free software; you can redistribute it and/or modify
   6 *  it under the terms of the GNU General Public License as published by
   7 *  the Free Software Foundation; either version 2 of the License, or
   8 *  (at your option) any later version.
   9 *
  10 *  This program is distributed in the hope that it will be useful,
  11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 *  GNU General Public License for more details.
  14 *
  15 *  You should have received a copy of the GNU General Public License
  16 *  along with this program; if not, write to the Free Software
  17 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18 *
  19 *  Davide Libenzi <davidel@xmailserver.org>
  20 *
  21 *
  22 *     $ gcc -o timerfd-test2 timerfd-test2.c -lrt
  23 *
  24 * NAME
  25 *      timerfd01.c
  26 * HISTORY
  27 *      28/05/2008 Initial contribution by Davide Libenzi <davidel@xmailserver.org>
  28 *      28/05/2008 Integrated to LTP by Subrata Modak <subrata@linux.vnet.ibm.com>
  29 *      2016-04-08 Deintegrated from LTP by Barret Rhoden <brho@cs.berkeley.edu>
  30 *              Ported to Akaros.  Added a few more tests.
  31 */
  32
  33#define _GNU_SOURCE
  34#include <sys/syscall.h>
  35#include <sys/types.h>
  36#include <sys/signal.h>
  37#include <sys/time.h>
  38#include <stdio.h>
  39#include <stdlib.h>
  40#include <string.h>
  41#include <unistd.h>
  42#include <signal.h>
  43#include <poll.h>
  44#include <fcntl.h>
  45#include <time.h>
  46#include <errno.h>
  47
  48#include <sys/timerfd.h>
  49#include <sys/select.h>
  50#include <parlib/alarm.h>
  51#include <parlib/uthread.h>
  52
  53struct tmr_type {
  54        int id;
  55        char const *name;
  56};
  57
  58unsigned long long getustime(int clockid)
  59{
  60        struct timespec tp;
  61
  62        if (clock_gettime((clockid_t) clockid, &tp)) {
  63                perror("clock_gettime");
  64                return 0;
  65        }
  66
  67        return 1000000ULL * tp.tv_sec + tp.tv_nsec / 1000;
  68}
  69
  70void set_timespec(struct timespec *tmr, unsigned long long ustime)
  71{
  72
  73        tmr->tv_sec = (time_t) (ustime / 1000000ULL);
  74        tmr->tv_nsec = (long)(1000ULL * (ustime % 1000000ULL));
  75}
  76
  77
  78long waittmr(int tfd, int timeo)
  79{
  80        u_int64_t ticks;
  81        fd_set rfds;
  82        struct timeval tv, *timeout = 0;
  83        int ret;
  84
  85        FD_ZERO(&rfds);
  86        FD_SET(tfd, &rfds);
  87        if (timeo != -1) {
  88                tv.tv_sec = timeo / 1000;
  89                tv.tv_usec = (timeo % 1000) * 1000;
  90                timeout = &tv;
  91        }
  92        ret = select(tfd + 1, &rfds, 0, 0, timeout);
  93        if (ret < 0) {
  94                perror("select");
  95                return -1;
  96        }
  97        if (ret == 0) {
  98                fprintf(stdout, "no ticks happened\n");
  99                return -1;
 100        }
 101        if (read(tfd, &ticks, sizeof(ticks)) != sizeof(ticks)) {
 102                perror("timerfd read");
 103                return -1;
 104        }
 105        return ticks;
 106}
 107
 108int main(int ac, char **av)
 109{
 110        int i, tfd;
 111        long ticks;
 112        unsigned long long tnow, ttmr;
 113        u_int64_t uticks;
 114        struct itimerspec tmr;
 115        struct tmr_type clks[] = {
 116                {CLOCK_MONOTONIC, "CLOCK MONOTONIC"},
 117                {CLOCK_REALTIME, "CLOCK REALTIME"},
 118        };
 119
 120        for (i = 0; i < sizeof(clks) / sizeof(clks[0]); i++) {
 121                fprintf(stdout,
 122                        "\n\n---------------------------------------\n");
 123                fprintf(stdout, "| testing %s\n", clks[i].name);
 124                fprintf(stdout, "---------------------------------------\n\n");
 125
 126                fprintf(stdout, "relative timer test (at 500 ms) ...\n");
 127                set_timespec(&tmr.it_value, 500 * 1000);
 128                set_timespec(&tmr.it_interval, 0);
 129                tnow = getustime(clks[i].id);
 130                if ((tfd = timerfd_create(clks[i].id, 0)) == -1) {
 131                        perror("timerfd");
 132                        return 1;
 133                }
 134                fprintf(stdout, "timerfd = %d\n", tfd);
 135
 136                if (timerfd_settime(tfd, 0, &tmr, NULL)) {
 137                        perror("timerfd_settime");
 138                        return 1;
 139                }
 140
 141                fprintf(stdout, "waiting timer ...\n");
 142                ticks = waittmr(tfd, -1);
 143                ttmr = getustime(clks[i].id);
 144                if (ticks <= 0)
 145                        fprintf(stdout, "whooops! no timer showed up!\n");
 146                else
 147                        fprintf(stdout, "got timer ticks (%ld) after %llu ms\n",
 148                                ticks, (ttmr - tnow) / 1000);
 149
 150                fprintf(stdout, "absolute timer test (at 500 ms) ...\n");
 151                tnow = getustime(clks[i].id);
 152                set_timespec(&tmr.it_value, tnow + 500 * 1000);
 153                set_timespec(&tmr.it_interval, 0);
 154                if (timerfd_settime(tfd, TFD_TIMER_ABSTIME, &tmr, NULL)) {
 155                        perror("timerfd_settime");
 156                        return 1;
 157                }
 158
 159                fprintf(stdout, "waiting timer ...\n");
 160                ticks = waittmr(tfd, -1);
 161                ttmr = getustime(clks[i].id);
 162                if (ticks <= 0)
 163                        fprintf(stdout, "whooops! no timer showed up!\n");
 164                else
 165                        fprintf(stdout, "got timer ticks (%ld) after %llu ms\n",
 166                                ticks, (ttmr - tnow) / 1000);
 167
 168                fprintf(stdout, "sequential timer test (100 ms clock) ...\n");
 169                tnow = getustime(clks[i].id);
 170                set_timespec(&tmr.it_value, tnow + 100 * 1000);
 171                set_timespec(&tmr.it_interval, 100 * 1000);
 172                if (timerfd_settime(tfd, TFD_TIMER_ABSTIME, &tmr, NULL)) {
 173                        perror("timerfd_settime");
 174                        return 1;
 175                }
 176
 177                fprintf(stdout, "sleeping 1 second ...\n");
 178                sleep(1);
 179                if (timerfd_gettime(tfd, &tmr)) {
 180                        perror("timerfd_gettime");
 181                        return 1;
 182                }
 183                fprintf(stdout, "timerfd_gettime returned:\n"
 184                        "\tit_value = { %ld, %ld } it_interval = { %ld, %ld }\n",
 185                        (long)tmr.it_value.tv_sec, (long)tmr.it_value.tv_nsec,
 186                        (long)tmr.it_interval.tv_sec,
 187                        (long)tmr.it_interval.tv_nsec);
 188                fprintf(stdout, "sleeping 1 second ...\n");
 189                sleep(1);
 190
 191                fprintf(stdout, "waiting timer ...\n");
 192                ticks = waittmr(tfd, -1);
 193                ttmr = getustime(clks[i].id);
 194                if (ticks <= 0)
 195                        fprintf(stdout, "whooops! no timer showed up!\n");
 196                else
 197                        fprintf(stdout, "got timer ticks (%ld) after %llu ms\n",
 198                                ticks, (ttmr - tnow) / 1000);
 199
 200                fprintf(stdout, "O_NONBLOCK test ...\n");
 201                tnow = getustime(clks[i].id);
 202                set_timespec(&tmr.it_value, 100 * 1000);
 203                set_timespec(&tmr.it_interval, 0);
 204                if (timerfd_settime(tfd, 0, &tmr, NULL)) {
 205                        perror("timerfd_settime");
 206                        return 1;
 207                }
 208                fprintf(stdout, "timerfd = %d\n", tfd);
 209
 210                fprintf(stdout, "waiting timer (flush the single tick) ...\n");
 211                ticks = waittmr(tfd, -1);
 212                ttmr = getustime(clks[i].id);
 213                if (ticks <= 0)
 214                        fprintf(stdout, "whooops! no timer showed up!\n");
 215                else
 216                        fprintf(stdout, "got timer ticks (%ld) after %llu ms\n",
 217                                ticks, (ttmr - tnow) / 1000);
 218
 219                fcntl(tfd, F_SETFL, fcntl(tfd, F_GETFL, 0) | O_NONBLOCK);
 220
 221                if (read(tfd, &uticks, sizeof(uticks)) > 0)
 222                        fprintf(stdout,
 223                                "whooops! timer ticks not zero when should have been\n");
 224                else if (errno != EAGAIN)
 225                        fprintf(stdout,
 226                                "whooops! bad errno value (%d = '%s')!\n",
 227                                errno, strerror(errno));
 228                else
 229                        fprintf(stdout, "success\n");
 230
 231                /* try a select loop with O_NONBLOCK */
 232                fd_set rfds;
 233                bool has_selected = FALSE;
 234                int ret;
 235
 236                FD_ZERO(&rfds);
 237                FD_SET(tfd, &rfds);
 238                set_timespec(&tmr.it_value, 1000000);
 239                set_timespec(&tmr.it_interval, 0);
 240                if (timerfd_settime(tfd, 0, &tmr, NULL)) {
 241                        perror("timerfd_settime");
 242                        exit(-1);
 243                }
 244                while (1) {
 245                        ret = read(tfd, &uticks, sizeof(uticks));
 246                        if (ret < 0) {
 247                                if (errno != EAGAIN) {
 248                                        perror("select read");
 249                                        exit(-1);
 250                                }
 251                        } else {
 252                                if (ret != sizeof(uticks)) {
 253                                        fprintf(stdout, "short read! (bad)\n");
 254                                        exit(-1);
 255                                }
 256                                if (uticks)
 257                                        break;
 258                        }
 259                        if (select(tfd + 1, &rfds, 0, 0, 0) < 0) {
 260                                perror("select");
 261                                return -1;
 262                        }
 263                        has_selected = TRUE;
 264                }
 265                if (!has_selected) {
 266                        fprintf(stdout, "Failed to try to select!\n");
 267                        exit(-1);
 268                }
 269                fprintf(stdout, "more success\n");
 270                fcntl(tfd, F_SETFL, fcntl(tfd, F_GETFL, 0) & ~O_NONBLOCK);
 271
 272                /* let's make sure it actually blocks too. */
 273                struct alarm_waiter waiter;
 274
 275                init_awaiter(&waiter, alarm_abort_sysc);
 276                waiter.data = current_uthread;
 277                set_awaiter_rel(&waiter, 1000000);
 278
 279                set_timespec(&tmr.it_value, 10000000);
 280                set_timespec(&tmr.it_interval, 0);
 281                if (timerfd_settime(tfd, 0, &tmr, NULL)) {
 282                        perror("timerfd_settime");
 283                        exit(-1);
 284                }
 285                set_alarm(&waiter);
 286                ret = read(tfd, &uticks, sizeof(uticks));
 287                unset_alarm(&waiter);
 288                if (ret > 0) {
 289                        fprintf(stdout,
 290                                "Failed to block when we should have!\n");
 291                        exit(-1);
 292                }
 293                fprintf(stdout, "done (still success)\n");
 294
 295                close(tfd);
 296        }
 297}
 298