Most recent kernel where this bug did not occur: all kernels Distribution: n/a Hardware Environment: x86 (and probably all others) Software Environment: n/a Problem Description: The POSIX.1 specification of setitimer() says that the call should fail with the error EINVAL if the microsecond (tv_usec) components of the value argument are not "canonical", that is: 0 <= tv_usec < 1000 FreeBSD 6.0 and Solaris 8 (the only other implementations that I have recently tested) honour the POSIX.1 requirement. On Linux, a non-canonical tv_usec value is instead normalised so that if, say, tv_usec is 2300000, then the 2000000 microseconds are added to the seconds (tv_sec) value (as 2 seconds), and the tv_usec value is taken as 300000 microseconds. This is not POSIX.1 conformant. Steps to reproduce: The behaviour can be demonstrated with the program below. /* t_setitimer.c A demonstration of the use of (real time) timers. Usage: real_timer [secs [usecs [int-secs [int-usecs]]]] Defaults: 2 0 0 0 The command-line arguments are the second and microsecond settings for the timers initial value and interval. */ #include <signal.h> #include <sys/time.h> #include <time.h> #include "lp_hdr.h" static volatile sig_atomic_t gotAlarm = 0; /* Set non-zero on receipt of SIGALRM */ static void sigalrmHandler(int sig) { gotAlarm = 1; } /* sigalrmHandler */ int main(int argc, char *argv[]) { struct itimerval itv; int maxSigs; /* # of signals to catch before exiting */ int sigCnt; /* # of signals so far caught */ struct sigaction sa; if (argc > 1 && strcmp(argv[1], "--help") == 0) usageErr("%s [secs [usecs [int-secs [int-usecs]]]]\n", argv[0]); sigCnt = 0; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = sigalrmHandler; if (sigaction(SIGALRM, &sa, NULL) == -1) errExit("sigaction"); /* Set timer from the command-line arguments */ itv.it_value.tv_sec = (argc > 1) ? getLong(argv[1], 0, "secs") : 2; itv.it_value.tv_usec = (argc > 2) ? getLong(argv[2], 0, "usecs") : 0; itv.it_interval.tv_sec = (argc > 3) ? getLong(argv[3], 0, "int-secs") : 0; itv.it_interval.tv_usec = (argc > 4) ? getLong(argv[4], 0, "int-usecs") : 0; /* Exit after 3 signals, or on first signal if interval is 0 */ maxSigs = (itv.it_interval.tv_sec == 0 && itv.it_interval.tv_usec == 0) ? 1 : 3; if (setitimer(ITIMER_REAL, &itv, 0) == -1) errExit("setitimer"); sigCnt = 0; for (;;) { while (1) { if (gotAlarm) { /* Did we get a signal? */ gotAlarm = 0; printf("Got signal\n"); sigCnt++; if (sigCnt >= maxSigs) { printf("That's all folks\n"); exit(EXIT_SUCCESS); } } } } }
Oops, the following line in the report: 0 <= tv_usec < 1000 Should of course have been: 0 <= tv_usec < 1000000
That's a known problem. Please see: http://kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=7d99b7d634d81bb372e03e4561c80430aa4cfac2 The check will be POSIX compliant after the grace period. Thanks, tglx
Thnaks -- that was quick turnaround.
The grace period is over and the interface is now correct.
Thanks Thomas. Yes, I spotted the fix went in 2.6.22, but forgot to close this report. Man page is already updated with the change ;-).