All of lore.kernel.org
 help / color / mirror / Atom feed
From: Michael Kerrisk <mtk-manpages@gmx.net>
To: Davide Libenzi <davidel@xmailserver.org>
Cc: lkml <linux-kernel@vger.kernel.org>
Subject: timerfd read only gets single byte?
Date: Tue, 17 Jul 2007 09:28:01 +0200	[thread overview]
Message-ID: <469C6F81.7070600@gmx.net> (raw)

Hi Davide,

While writing a test program to incorporate into the timerfd.2 man page, I
think I've found a bug.  It looks like only the least significant byte of
ticks is being returned from read(2), even though I am providing a 4 byte
buffer.

The test program takes 3 command line arguments:

1) seconds for the initial expiration
2) seconds for the timer interval
3) number of timer expirations to catch before terminating

I tried running this program and suspending it for a few minutes, to see if
I could get a large overrun value.  When I do this on 2.6.22-rc4 (the built
kernel I have to hand), I see the following:

============
$ ./timerfd_demo 1 1 500
0.000: timer started
1.005: read: 1; total=1
2.005: read: 1; total=2
3.005: read: 1; total=3
4.005: read: 1; total=4
5.006: read: 1; total=5
^Z
[1]+  Stopped                 ./timerfd_demo 1 1 500
$ date
Tue Jul 17 09:18:11 CEST 2007
$ date
Tue Jul 17 09:23:40 CEST 2007
$ fg
./timerfd_demo 1 1 500
339.769: read: 78; total=83
340.004: read: 1; total=84
341.004: read: 1; total=85
^C
==============

The after bringing the program back into the foreground, I would have
expected to get an overrun count of 334 or thereabouts, but it looks as
though I'm only getting the least significant byte from read(2).

Cheers,

Michael


/* Link with -lrt */

#define _GNU_SOURCE
#include <sys/syscall.h>
#include <unistd.h>
#include <time.h>
#if defined(__i386__)
#define __NR_timerfd 322
#endif

static int
timerfd(int ufd, int clockid, int flags, struct itimerspec *utmr) {
    return syscall(__NR_timerfd, ufd, clockid, flags, utmr);
}

#define TFD_TIMER_ABSTIME (1 << 0)

////////////////////////////////////////////////////////////

// #include <sys/timerfd.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>     /* Definition of uint32_t */

#define die(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)

static void
print_elapsed_time(void)
{
    static struct timespec start;
    struct timespec curr;
    static int first_call = 1;
    int secs, nsecs;

    if (first_call) {
        first_call = 0;
        if (clock_gettime(CLOCK_MONOTONIC, &start) == -1)
            die("clock_gettime");
    }

    if (clock_gettime(CLOCK_MONOTONIC, &curr) == -1)
        die("clock_gettime");

    secs = curr.tv_sec - start.tv_sec;
    nsecs = curr.tv_nsec - start.tv_nsec;
    if (nsecs < 0) {
        secs--;
        nsecs += 1000000000;
    }
    printf("%d.%03d: ", secs, (nsecs + 500000) / 1000000);
}

int
main(int argc, char *argv[])
{
    struct itimerspec utmr;
    int max_exp, tot_exp, tfd;
    struct timespec now;
    uint32_t exp;
    ssize_t s;

    if ((argc != 2) && (argc != 4)) {
        fprintf(stderr, "%s init-secs [interval-secs max-exp]\n",
                argv[0]);
        exit(EXIT_FAILURE);
    }

    if (clock_gettime(CLOCK_REALTIME, &now) == -1)
        die("clock_gettime");

    /* Create a CLOCK_REALTIME absolute timer with initial
       expiration and interval as specified in command line */

    utmr.it_value.tv_sec = now.tv_sec + atoi(argv[1]);
    utmr.it_value.tv_nsec = now.tv_nsec;
    if (argc == 2) {
        utmr.it_interval.tv_sec = 0;
        max_exp = 1;
    } else {
        utmr.it_interval.tv_sec = atoi(argv[2]);
        max_exp = atoi(argv[3]);
    }
    utmr.it_interval.tv_nsec = 0;

    tfd = timerfd(-1, CLOCK_REALTIME, TFD_TIMER_ABSTIME, &utmr);
    if (tfd == -1)
        die("timerfd");

    print_elapsed_time();
    printf("timer started\n");

    exp = 0; // ????? Without this initialization, the results from
             // read() are strange; it appears that read() is only
             // returning one byte of tick information, not four.
    for (tot_exp = 0; tot_exp < max_exp;) {
        s = read(tfd, &exp, sizeof(uint32_t));
        if (s != sizeof(uint32_t))
            die("read");

        tot_exp += exp;
        print_elapsed_time();
        printf("read: %u; total=%d\n", exp, tot_exp);
    }

    exit(EXIT_SUCCESS);
}


             reply	other threads:[~2007-07-17  8:11 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-07-17  7:28 Michael Kerrisk [this message]
     [not found] ` <750c918d0707170424v5e4187dducb1dcaeea5ad9db7@mail.gmail.com>
2007-07-17 11:31   ` Fwd: timerfd read only gets single byte? Davi Arnaut
2007-07-17 19:19     ` Davide Libenzi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=469C6F81.7070600@gmx.net \
    --to=mtk-manpages@gmx.net \
    --cc=davidel@xmailserver.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.