bug-glibc
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Posix timers


From: Joe English
Subject: Posix timers
Date: Sat, 01 Feb 2003 11:21:49 -0800

Hello, and apologies if this is not the appropriate mailing list.

I've noticed some odd behaviour with the POSIX timers
interface (timer_create() / timer_settime()) on Linux/x86
when using a periodic timer.  (Test program below).

It appears that timer_settime() rounds it_interval up to
the nearest multiple of 1/HZ seconds (10 milliseconds in
this case) and then *adds* another 1/HZ.  So the smallest
achievable interval is 20 milliseconds.

I've tested this under a handful of Linux/x86 distributions:
a patched RedHat 7 (glibc 2.2.4, kernel 2.4.14-smp),
this week's Debian sarge (glibc 2.2.5, kernels 2.4.18
and 2.4.18-smp) and Mandrake 9.0 (glibc 2.2.5, kernel 2.4.20-2mdk),
the problem appears on all these platforms.

In addition, on some (but not all) of the above systems,
the signal handler is never invoked at all if I use
sigev_signo = SIGRTMIN in the timer_create() call.
Other signals (SIGRTMAX, SIGALRM) work OK.  Oddly,
this depends on where the program is compiled, not
where it's run.

Most unusually, under Red Hat 8.0 (glibc "2.2.93", kernel
2.4.18-14smp) the timer resolution works *far better*
than expected.  On this platform it appears to be accurate
to within a few microseconds, with any interval above 4
milliseconds.  I would have expected to see at best 1/512
seconds granularity (the RH kernel sets HZ to 512 instead
of the usual 100), which is the case with BSD interval
timers on that platform.

So my questions: am I doing something wrong in the code?
If not, is this a known bug in glibc and/or the kernel?
What's different in Red Hat 8.0 that makes it work so well?
Can we expect to see these improvements in mainline glibc
versions/other Linux distros in the future?

Thanks for any advice.


====< test driver - cut here >====

/* Compile with: cc timertest -lrt
 * Usage:
 *      ./a.out [#microseconds/step [#steps]]
 */

#define POSIX_SOURCE 1
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>

static volatile sig_atomic_t timer_tick = 0;

void sigalarm(int signo)
{
    ++timer_tick;
    /* write(2,".",1); */
}

int main(int argc, char *argv[])
{
    clock_t clock = CLOCK_REALTIME;
    int signum = SIGRTMAX;
    int microsec = 10000;
    int nsteps = 100;
    int status;
    struct timeval time0, time1;
    double dt;
    timer_t timer_id;
    struct itimerspec ts;
    struct sigevent se;
    struct sigaction act;
    sigset_t sigmask;

    /* Command-line arguments: */
    if (argc >= 2)
        microsec = atol(argv[1]);

    if (argc >= 3)
        nsteps = atol(argv[2]);

    /* Set up signal handler: */
    sigfillset(&act.sa_mask);
    act.sa_flags = 0;
    act.sa_handler = sigalarm;
    sigaction(signum, &act, NULL);

    /* Set up timer: */
    memset(&se, 0, sizeof(se));
    se.sigev_notify = SIGEV_SIGNAL;
    se.sigev_signo = signum;
    se.sigev_value.sival_int = 0;
    status = timer_create(clock, &se, &timer_id);
    if (status < 0) {
        perror("timer_create");
        return EXIT_FAILURE;
    }

    /* Start timer: */
    ts.it_interval.tv_sec =   microsec / 1000000;
    ts.it_interval.tv_nsec = (microsec % 1000000) * 1000;
    ts.it_value = ts.it_interval;
    status = timer_settime(timer_id, 0, &ts, NULL);
    if (status < 0) {
        perror("timer_settime");
        return EXIT_FAILURE;
    }

    /* Tick */
    gettimeofday(&time0, NULL);

    /* Loop: */
    sigemptyset(&sigmask);
    while (timer_tick < nsteps)
        sigsuspend(&sigmask);

    /* Tock */
    gettimeofday(&time1, NULL);
    time1.tv_usec -= time0.tv_usec;
    time1.tv_sec  -= time0.tv_sec;
    dt = (double)time1.tv_sec + (((double)time1.tv_usec) / 1000000.0);

    printf("\nTotal time: %f (%f%%)\n",
                dt, (dt * 100.0 * 1000000.0) / (nsteps * (double)microsec) );
    printf("Overruns: %d\n", timer_getoverrun(timer_id));

    timer_delete(timer_id);

    return EXIT_SUCCESS;
}

/*EOF*/

====< test driver - cut here >====


--Joe English

  address@hidden




reply via email to

[Prev in Thread] Current Thread [Next in Thread]