man-pages/man2/getitimer.2

215 lines
5.6 KiB
Groff
Raw Normal View History

2004-11-03 13:51:07 +00:00
.\" Copyright 7/93 by Darren Senn <sinster@scintilla.santa-clara.ca.us>
.\" Based on a similar page Copyright 1992 by Rick Faith
.\" May be freely distributed
.\" Modified Tue Oct 22 00:22:35 EDT 1996 by Eric S. Raymond <esr@thyrsus.com>
.\" 2005-04-06 mtk, Matthias Lang <matthias@corelatus.se>
.\" Noted MAX_SEC_IN_JIFFIES ceiling
.TH GETITIMER 2 2008-04-24 "Linux" "Linux Programmer's Manual"
2004-11-03 13:51:07 +00:00
.SH NAME
getitimer, setitimer \- get or set value of an interval timer
.SH SYNOPSIS
2006-03-08 02:48:53 +00:00
.nf
2004-11-03 13:51:07 +00:00
.B #include <sys/time.h>
.sp
2006-03-08 02:48:53 +00:00
.BI "int getitimer(int " which ", struct itimerval *" value );
.br
.BI "int setitimer(int " which ", const struct itimerval *" value ,
.BI " struct itimerval *" ovalue );
.fi
2004-11-03 13:51:07 +00:00
.SH DESCRIPTION
The system provides each process with three interval timers,
each decrementing in a distinct time domain.
When any timer expires, a signal is sent to the
2004-11-03 13:51:07 +00:00
process, and the timer (potentially) restarts.
.TP 1.5i
.B ITIMER_REAL
decrements in real time, and delivers
.B SIGALRM
upon expiration.
.TP
.B ITIMER_VIRTUAL
decrements only when the process is executing, and delivers
.B SIGVTALRM
upon expiration.
.TP
.B ITIMER_PROF
decrements both when the process executes and when the system is executing
on behalf of the process.
Coupled with
2004-11-03 13:51:07 +00:00
.BR ITIMER_VIRTUAL ,
this timer is usually used to profile the time spent by the
application in user and kernel space.
2004-11-03 13:51:07 +00:00
.B SIGPROF
is delivered upon expiration.
.LP
Timer values are defined by the following structures:
.PD 0
2007-12-23 14:14:04 +00:00
.in +4n
2004-11-03 13:51:07 +00:00
.nf
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 */
2005-06-13 09:01:49 +00:00
2004-11-03 13:51:07 +00:00
struct itimerval {
struct timeval it_interval; /* next value */
struct timeval it_value; /* current value */
};
2007-12-23 14:14:04 +00:00
2004-11-03 13:51:07 +00:00
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
.fi
2007-12-23 14:14:04 +00:00
.in
2004-11-03 13:51:07 +00:00
.PD
.LP
The function
.BR getitimer ()
2004-11-03 13:51:07 +00:00
fills the structure indicated by
.I value
with the current setting for the timer indicated by
.I which
(one of
.BR ITIMER_REAL ,
.BR ITIMER_VIRTUAL ,
or
.BR ITIMER_PROF ).
The element
.I it_value
2004-11-03 13:51:07 +00:00
is set to the amount of time remaining on the timer, or zero if the timer
is disabled.
Similarly,
.I it_interval
2004-11-03 13:51:07 +00:00
is set to the reset value.
The function
.BR setitimer ()
2004-11-03 13:51:07 +00:00
sets the indicated timer to the value in
.IR value .
If
.I ovalue
is non-NULL, the old value of the timer is stored there.
2004-11-03 13:51:07 +00:00
.LP
Timers decrement from
.I it_value
to zero, generate a signal, and reset to
.IR it_interval .
A timer which is set to zero
.RI ( it_value
is zero or the timer expires and
.I it_interval
is zero) stops.
.LP
Both
.I tv_sec
and
.I tv_usec
are significant in determining the duration of a timer.
.LP
Timers will never expire before the requested time,
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 */
2005-06-13 09:01:49 +00:00
but may expire some (short) time afterwards, which depends
on the system timer resolution and on the system load; see
.BR time (7).
2005-06-21 13:50:30 +00:00
(But see BUGS below.)
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 */
2005-06-13 09:01:49 +00:00
Upon expiration, a signal will be generated and the timer reset.
If the timer expires while the process is active (always true for
2006-03-20 00:52:31 +00:00
.BR ITIMER_VIRTUAL )
the signal will be delivered immediately when generated.
Otherwise the
2004-11-03 13:51:07 +00:00
delivery will be offset by a small time dependent on the system loading.
.SH "RETURN VALUE"
On success, zero is returned.
On error, \-1 is returned, and
2004-11-03 13:51:07 +00:00
.I errno
is set appropriately.
.SH ERRORS
.TP
.B EFAULT
.I value
or
.I ovalue
are not valid pointers.
.TP
.B EINVAL
.I which
is not one of
.BR ITIMER_REAL ,
2006-03-20 00:52:31 +00:00
.BR ITIMER_VIRTUAL ,
2004-11-03 13:51:07 +00:00
or
.BR ITIMER_PROF ;
or (since Linux 2.6.22) one of the
.I tv_usec
fields contains a value outside the range 0 to 999999.
.SH "CONFORMING TO"
POSIX.1-2001, SVr4, 4.4BSD (this call first appeared in 4.2BSD).
2008-03-19 15:09:59 +00:00
.\" FIXME . Mar 08: The next POSIX.1 revisions marks getitimer() and
.\" setitimer() obsolete.
2006-07-22 15:54:34 +00:00
.SH NOTES
A child created via
.BR fork (2)
does not inherit its parent's interval timers.
Interval timers are preserved across an
2006-07-22 15:54:34 +00:00
.BR execve (2).
POSIX.1 leaves the
interaction between
.BR setitimer()
2008-06-27 12:10:15 +00:00
and the three interfaces
.BR alarm (2),
.BR sleep (3),
and
.BR usleep (3)
unspecified.
2004-11-03 13:51:07 +00:00
.SH BUGS
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 */
2005-06-13 09:01:49 +00:00
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.
2007-12-19 06:29:23 +00:00
Under very heavy loading, an
2004-11-03 13:51:07 +00:00
.B ITIMER_REAL
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 */
2005-06-13 09:01:49 +00:00
timer may expire before the signal from a previous expiration
has been delivered.
2004-11-03 13:51:07 +00:00
The second signal in such an event will be lost.
On Linux kernels before 2.6.16, timer values are represented in jiffies.
If a request is made set a timer with a value whose jiffies
2007-06-22 17:16:20 +00:00
representation exceeds
.B MAX_SEC_IN_JIFFIES
(defined in
.IR include/linux/jiffies.h ),
then the timer is silently truncated to this ceiling value.
On Linux/i386 (where, since Linux 2.6.13,
the default jiffy is 0.004 seconds),
this means that the ceiling value for a timer is
approximately 99.42 days.
Since Linux 2.6.16,
the kernel uses a different internal representation for times,
and this ceiling is removed.
2007-12-24 17:31:35 +00:00
On certain systems (including i386),
Linux kernels before version 2.6.12 have a bug which will produce
premature timer expirations of up to one jiffy under some circumstances.
This bug is fixed in kernel 2.6.12.
.\" 4 Jul 2005: It looks like this bug may remain in 2.4.x.
.\" http://lkml.org/lkml/2005/7/1/165
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 */
2005-06-13 09:01:49 +00:00
POSIX.1-2001 says that
.BR setitimer ()
should fail if a
.I tv_usec
value is specified that is outside of the range 0 to 999999.
However, in kernels up to and including 2.6.21,
Linux does not give an error, but instead silently
adjusts the corresponding seconds value for the timer.
From kernel 2.6.22 onwards,
this non-conformance has been repaired:
an improper
.I tv_usec
value results in an
.B EINVAL
error.
.\" Bugzilla report 25 Apr 2006:
.\" http://bugzilla.kernel.org/show_bug.cgi?id=6443
.\" "setitimer() should reject non-canonical arguments"
2007-05-16 18:25:50 +00:00
.SH "SEE ALSO"
.BR gettimeofday (2),
.BR sigaction (2),
.BR signal (2),
.BR timerfd_create (2),
2007-05-16 18:25:50 +00:00
.BR time (7)