public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* timerfd read only gets single byte?
@ 2007-07-17  7:28 Michael Kerrisk
       [not found] ` <750c918d0707170424v5e4187dducb1dcaeea5ad9db7@mail.gmail.com>
  0 siblings, 1 reply; 3+ messages in thread
From: Michael Kerrisk @ 2007-07-17  7:28 UTC (permalink / raw)
  To: Davide Libenzi; +Cc: lkml

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);
}


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: Fwd: timerfd read only gets single byte?
       [not found] ` <750c918d0707170424v5e4187dducb1dcaeea5ad9db7@mail.gmail.com>
@ 2007-07-17 11:31   ` Davi Arnaut
  2007-07-17 19:19     ` Davide Libenzi
  0 siblings, 1 reply; 3+ messages in thread
From: Davi Arnaut @ 2007-07-17 11:31 UTC (permalink / raw)
  To: Michael Kerrisk; +Cc: Davide Libenzi, lkml

Michael Kerrisk wrote:
 >
> 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
> 
> [...]

put_user copies sizeof(*ptr) bytes to user space.

Signed-off-by: Davi Arnaut <davi@haxent.com.br


diff --git a/fs/timerfd.c b/fs/timerfd.c
index af9eca5..e9f73f5 100644
--- a/fs/timerfd.c
+++ b/fs/timerfd.c
@@ -140,7 +140,8 @@ static ssize_t timerfd_read(struct file *file, char
__user *buf, size_t count,
 	}
 	spin_unlock_irq(&ctx->wqh.lock);
 	if (ticks)
-		res = put_user(ticks, buf) ? -EFAULT: sizeof(ticks);
+		res = put_user(ticks, ((u32 __user *)buf)) ? -EFAULT :
+							      sizeof(ticks);
 	return res;
 }


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: Fwd: timerfd read only gets single byte?
  2007-07-17 11:31   ` Fwd: " Davi Arnaut
@ 2007-07-17 19:19     ` Davide Libenzi
  0 siblings, 0 replies; 3+ messages in thread
From: Davide Libenzi @ 2007-07-17 19:19 UTC (permalink / raw)
  To: Davi Arnaut; +Cc: Michael Kerrisk, lkml

On Tue, 17 Jul 2007, Davi Arnaut wrote:

> Michael Kerrisk wrote:
>  >
> > 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
> > 
> > [...]
> 
> put_user copies sizeof(*ptr) bytes to user space.
> 
> Signed-off-by: Davi Arnaut <davi@haxent.com.br
> 
> 
> diff --git a/fs/timerfd.c b/fs/timerfd.c
> index af9eca5..e9f73f5 100644
> --- a/fs/timerfd.c
> +++ b/fs/timerfd.c
> @@ -140,7 +140,8 @@ static ssize_t timerfd_read(struct file *file, char
> __user *buf, size_t count,
>  	}
>  	spin_unlock_irq(&ctx->wqh.lock);
>  	if (ticks)
> -		res = put_user(ticks, buf) ? -EFAULT: sizeof(ticks);
> +		res = put_user(ticks, ((u32 __user *)buf)) ? -EFAULT :
> +							      sizeof(ticks);
>  	return res;
>  }

Yeah, thanks. But talking to Michael, we think it's better to use an u64 
like we do in the eventfd.



- Davide



^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2007-07-17 19:19 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-07-17  7:28 timerfd read only gets single byte? Michael Kerrisk
     [not found] ` <750c918d0707170424v5e4187dducb1dcaeea5ad9db7@mail.gmail.com>
2007-07-17 11:31   ` Fwd: " Davi Arnaut
2007-07-17 19:19     ` Davide Libenzi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox