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