timer_getoverrun() doesn't behave as expected when using sleep()

Posted by dlp on Stack Overflow See other posts from Stack Overflow or by dlp
Published on 2012-07-08T01:06:50Z Indexed on 2012/07/08 3:15 UTC
Read the original article Hit count: 190

Filed under:
|
|

Here is a program that uses a POSIX per-process timer alongside the sleep subroutine. The signal used by the timer has been set to SIGUSR1 rather than SIGALRM, since SIGALRM may be used internally by sleep, but it still doesn't seem to work.

I have run the program using the command line timer-overruns -d 1 -n 10000000 (1 cs interval) so, in theory, we should expect 100 overruns between calls to sigwaitinfo. However, timer_getoverrun returns 0.

I have also tried a version using a time-consuming for loop to introduce the delay. In this case, overruns are recorded.

Does anyone know why this happens? I am running a 3.4 Linux kernel.

Program source

/*
 * timer-overruns.c
 */

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <time.h>

// Signal to be used for timer expirations
#define TIMER_SIGNAL SIGUSR1

int main(int argc, char **argv) {
    int opt;
    int d = 0;
    int r = 0; // Repeat indefinitely
    struct itimerspec its;
    its.it_interval.tv_sec = 0;
    its.it_interval.tv_nsec = 0;

    // Parse arguments
    while ((opt = getopt(argc, argv, "d:r:s:n:")) != -1) {
        switch (opt) {
        case 'd': // Delay before calling sigwaitinfo()
            d = atoi(optarg);
            break;
        case 'r': // Number of times to call sigwaitinfo()
            r = atoi(optarg);
            break;
        case 's': // Timer interval (seconds)
            its.it_interval.tv_sec = its.it_value.tv_sec = atoi(optarg);
            break;
        case 'n': // Timer interval (nanoseconds)
            its.it_interval.tv_nsec = its.it_value.tv_nsec = atoi(optarg);
            break;
        default: /* '?' */
            fprintf(stderr,
                    "Usage: %s [-d signal_accept_delay] [-r repetitions] [-s interval_seconds] [-n interval_nanoseconds]\n",
                    argv[0]);
            exit(EXIT_FAILURE);
        }
    }

    // Check sanity of command line arguments
    short e = 0;

    if (d < 0) {
        fprintf(stderr, "Delay (-d) cannot be negative!\n");
        e++;
    }
    if (r < 0) {
        fprintf(stderr, "Number of repetitions (-r) cannot be negative!\n");
        e++;
    }
    if (its.it_interval.tv_sec < 0) {
        fprintf(stderr, "Interval seconds value (-s) cannot be negative!\n");
        e++;
    }
    if (its.it_interval.tv_nsec < 0) {
        fprintf(stderr, "Interval nanoseconds value (-n) cannot be negative!\n");
        e++;
    }
    if (its.it_interval.tv_nsec > 999999999) {
        fprintf(stderr, "Interval nanoseconds value (-n) must be < 1 second.\n");
        e++;
    }

    if (e > 0)
        exit(EXIT_FAILURE);

    // Set default values if not specified
    if (its.it_interval.tv_sec == 0 && its.it_interval.tv_nsec == 0) {
        its.it_interval.tv_sec = its.it_value.tv_sec = 1;
        its.it_value.tv_nsec = 0;
    }

    printf("Running with timer delay %d.%09d seconds\n",
            (int) its.it_interval.tv_sec, (int) its.it_interval.tv_nsec);

    // Will be waiting for signals synchronously, so block the one in use.  
    sigset_t sigset;

    sigemptyset(&sigset);
    sigaddset(&sigset, TIMER_SIGNAL);
    sigprocmask(SIG_BLOCK, &sigset, NULL );

    // Create and arm the timer
    struct sigevent sev;
    timer_t timer;

    sev.sigev_notify = SIGEV_SIGNAL;
    sev.sigev_signo = TIMER_SIGNAL;
    sev.sigev_value.sival_ptr = timer;

    timer_create(CLOCK_REALTIME, &sev, &timer);
    timer_settime(timer, TIMER_ABSTIME, &its, NULL );

    // Signal handling loop
    int overruns;
    siginfo_t si;

    // Make the loop infinite if r = 0
    if (r == 0)
        r = -1;

    while (r != 0) {
        // Sleeping should cause overruns
        if (d > 0)
            sleep(d);

        sigwaitinfo(&sigset, &si);

        // Check that the signal is from the timer
        if (si.si_code != SI_TIMER)
            continue;

        overruns = timer_getoverrun(timer);
        if (overruns > 0) {
            printf("Timer overrun occurred for %d expirations.\n", overruns);
        }

        // Decrement r if not repeating indefinitely
        if (r > 0)
            r--;
    }

    return EXIT_SUCCESS;
}

© Stack Overflow or respective owner

Related posts about c

    Related posts about linux