mirror of https://github.com/mkerrisk/man-pages
Salut Olivier (and Nishanth),
Regarding man page documentation of the problem of short sleeps for setiteimer(2)... > > -- pointers to those threads > > http://bugzilla.kernel.org/show_bug.cgi?id=4569 > http://lkml.org/lkml/2005/4/29/163 > > > -- indications of which kernel versions show this bahaviour > > AFAIK, all versions as far as x86 is concerned. > Dunno if it is hardware specific. > > > -- a (short) test program to demonstrate it, if you have one. > > See the bugzilla bug's attachments Sorry for the long delay in following this up, but I've got to it now. I tweaked your suggestions slightly: {{ Timers will never expire before the requested time, -instead expiring some short, constant time afterwards, dependent -on the system timer resolution (currently 10ms). +but may expire some (short) time afterwards, which depends +on the system timer resolution and on the system load. +Upon expiration, a signal will be generated and the timer reset. +If the timer expires while the process is active (always true for +On certain systems (including x86), the Linux kernel has a bug which will +produce premature timer expirations of up to one jiffy under some +circumstances. }} Thanks for this bug reporet, Nishanth: if and when your changes are accepted, and the problem is thus fixed, could you please send me a notification of that fact, and I can then further amend the manual pages. Cheers, Michael /* itimer_short_interval_bug.c June 2005 In current Linux kernels, an interval timer set using setitimer() can sometimes sleep *less* than the specified interval. This program demonstrates the behaviour by looping through all itimer values from 1 microsecond upwards, in one microsecond steps. */ /* Adapted from a program by Olivier Croquette, June 2005 */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/time.h> #include <sys/wait.h> typedef unsigned long long int u_time_t; /* in microsecs */ static int handler_flag; /* return time as a number of microsecs */ static u_time_t gettime(void ) { struct timeval tv; if ( gettimeofday(&tv, NULL) == -1) { perror("gettimeofday()"); return 0; } return (tv.tv_usec + tv.tv_sec * 1000000LL); } static void handler (int sig, siginfo_t *siginfo, void *context) { handler_flag++; return ; } /* Sleep for 'time' microsecs. */ static int isleep(u_time_t time) { struct itimerval newtv; sigset_t sigset; struct sigaction sigact; if (time == 0) return 0; /* block SIGALRM */ sigemptyset (&sigset); sigaddset (&sigset, SIGALRM); sigprocmask (SIG_BLOCK, &sigset, NULL); /* set up our handler */ sigact.sa_sigaction = handler; sigemptyset(&sigact.sa_mask); sigact.sa_flags = SA_SIGINFO; sigaction (SIGALRM, &sigact, NULL); newtv.it_interval.tv_sec = 0; newtv.it_interval.tv_usec = 0; newtv.it_value.tv_sec = time / 1000000; newtv.it_value.tv_usec = time % 1000000; if (setitimer(ITIMER_REAL,&newtv,NULL) == -1) { perror("setitimer(set)"); return 1; } sigemptyset (&sigset); sigsuspend (&sigset); return 0; } int main(int argc, char *argv[]) { u_time_t wait; int loop, numLoops; u_time_t t1, t2; u_time_t actual; long long minDiff, maxDiff, totDiff, diff; int numFail = 0; if (argc != 2) { fprintf(stderr, "Usage: %s num-loops\n", argv[0]); exit(EXIT_FAILURE); } /* if */ numLoops = atoi(argv[1]); setbuf(stdout, NULL); for (wait = 1; ; wait++) { maxDiff = 0; numFail = 0; totDiff = 0; minDiff = -wait; if (wait % 10000 == 0) printf("%llu\n", wait); for (loop = 0; loop < numLoops; loop++) { t1 = gettime(); handler_flag = 0; isleep(wait); if ( handler_flag != 1 ) printf("Problem with the handler flag (%d)!\n", handler_flag); t2 = gettime(); actual = t2 - t1; if ( actual < wait ) { diff = actual - wait; if (diff < maxDiff) maxDiff = diff; if (diff > minDiff) minDiff = diff; totDiff += diff; numFail++; } /* if */ } /* for */ if (numFail > 0) printf("%llu: %3d fail (%4lld %4lld; avg=%6.1f)\n", wait, numFail, minDiff, maxDiff, (double) totDiff / numFail); } /* for */ return 0; } /* main */
This commit is contained in:
parent
561aa928db
commit
c13fcab060
|
@ -53,6 +53,7 @@ Timer values are defined by the following structures:
|
|||
.PD 0
|
||||
.RS .5i
|
||||
.nf
|
||||
|
||||
struct itimerval {
|
||||
struct timeval it_interval; /* next value */
|
||||
struct timeval it_value; /* current value */
|
||||
|
@ -107,10 +108,10 @@ and
|
|||
are significant in determining the duration of a timer.
|
||||
.LP
|
||||
Timers will never expire before the requested time,
|
||||
instead expiring some short, constant time afterwards, dependent
|
||||
on the system timer resolution (currently 10ms). Upon expiration, a
|
||||
signal will be generated and the timer reset. If the timer expires
|
||||
while the process is active (always true for
|
||||
but may expire some (short) time afterwards, which depends
|
||||
on the system timer resolution and on the system load.
|
||||
Upon expiration, a signal will be generated and the timer reset.
|
||||
If the timer expires while the process is active (always true for
|
||||
.BR ITIMER_VIRT )
|
||||
the signal will be delivered immediately when generated. Otherwise the
|
||||
delivery will be offset by a small time dependent on the system loading.
|
||||
|
@ -141,11 +142,13 @@ POSIX.1-2001, SVr4, 4.4BSD (this call first appeared in 4.2BSD).
|
|||
.BR sigaction (2),
|
||||
.BR signal (2)
|
||||
.SH BUGS
|
||||
Under Linux, the generation and delivery of a signal are distinct, and
|
||||
there each signal is permitted only one outstanding event. It's therefore
|
||||
conceivable that under pathologically heavy loading,
|
||||
The generation and delivery of a signal are distinct, and
|
||||
only one instance of each of the signals listed above may be pending
|
||||
for a process.
|
||||
Under very heavy loading, an
|
||||
.B ITIMER_REAL
|
||||
will expire before the signal from a previous expiration has been delivered.
|
||||
timer may expire before the signal from a previous expiration
|
||||
has been delivered.
|
||||
The second signal in such an event will be lost.
|
||||
|
||||
On Linux, timer values are represented in jiffies.
|
||||
|
@ -158,6 +161,11 @@ On Linux 2.6 on x86 (where a jiffy is 0.001 seconds),
|
|||
this means that the ceiling value for a timer is
|
||||
approximately 24.86 days.
|
||||
|
||||
On certain systems (including x86), the Linux kernel has a bug which will
|
||||
produce premature timer expirations of up to one jiffy under some
|
||||
circumstances.
|
||||
.\" As at June 2005, the above holds in 2.4.x and 2.6.c (e.g., 2.6.12.)
|
||||
|
||||
POSIX.1 says that
|
||||
.B setitimer
|
||||
should fail if a
|
||||
|
|
Loading…
Reference in New Issue