|
Home > Archive > Unix Programming > October 2006 > POSIX timers timer_settime() behavior for dates in the past
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
POSIX timers timer_settime() behavior for dates in the past
|
|
|
| Hello everyone,
I'm still playing with the POSIX timers API. My platform is x86 running
Linux 2.6.16.28 patched with the high-resolution timer subsystem.
http://www.tglx.de/hrtimers.html
http://www.tglx.de/projects/hrtimer...6.16-hrt6.patch
I'm seeing unexpected behavior from timer_settime().
int timer_settime(timer_t timerid, int flags,
const struct itimerspec *value, struct itimerspec *ovalue);
timer_settime() is used to arm a timer. If the TIMER_ABSTIME flag is
set, then the timer should fire when the appropriate clock reaches the
date specified by value. If that date is in the past, the timer should
fire immediately.
SUSv2 states:
"If the flag TIMER_ABSTIME is set in the argument flags, timer_settime()
behaves as if the time until next expiration is set to be equal to the
difference between the absolute time specified by the it_value member of
value and the current value of the clock associated with timerid. That
is, the timer expires when the clock reaches the value specified by the
it_value member of value. If the specified time has already passed, the
function succeeds and the expiration notification is made."
http://www.opengroup.org/onlinepubs...getoverrun.html
(I don't suppose SUSv3 changed that behavior.)
In my tests, when timer_settime is called with an expiration date in the
past, the timer takes a *LONG* time to fire.
Here's a run-down of the code provided below:
I switch to a SCHED_RR scheduling policy. In other words, whenever my
process wants the CPU, it gets it. (No other SCHED_RR or SCHED_FIFO
processes on the system.) I mask the signal that will be delivered on
timer expiration. I then arm a timer with an expiration date in the
past, check whether the signal is pending, and block waiting for the
signal. I then print how long I've had to wait.
# ./a.out
RESOLUTION=800 ns
NOW=8663.440797657
SLEEPING 1 SECOND...
NOW=8664.440831177
NOW=8664.440868945
NOW=8664.474870432
nsdiff=34001487 ns i.e. 34 ms
I'm starting to suspect there is a bug in the timer subsystem? It might
have been corrected in the patches for 2.6.17 or 2.6.18 (I'm not sure
the fixes are back-ported. What does the program print on your platform?
#include <stdio.h> // printf, puts, perror
#include <string.h> // memset
#include <unistd.h> // sleep
#include <signal.h> // sig*
#include <sched.h> // sched_setscheduler
#include <time.h> // clock_gettime, timer_*
#define ZERO(type, name) type name; memset(&name, 0, sizeof name)
#define SIG_TIMER_EXPIRATION SIGRTMIN
#define CLOCK_TYPE CLOCK_MONOTONIC
void set_SCHED_RR(void)
{
ZERO(struct sched_param, param);
param.sched_priority = 66;
if (sched_setscheduler(0, SCHED_RR, ¶m) != 0)
perror("sched_setscheduler");
}
struct timespec get_time_stamp(void)
{
ZERO(struct timespec, now);
if (clock_gettime(CLOCK_TYPE, &now) != 0) perror("clock_gettime");
printf("NOW=%ld.%09ld\n", now.tv_sec, now.tv_nsec);
return now;
}
int main(void)
{
set_SCHED_RR();
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIG_TIMER_EXPIRATION);
sigprocmask(SIG_BLOCK, &set, NULL);
ZERO(struct timespec, reso);
if (clock_getres(CLOCK_TYPE, &reso) != 0) perror("clock_getres");
printf("RESOLUTION=%ld ns\n", reso.tv_sec*1000000000+reso.tv_nsec);
timer_t timer;
ZERO(struct sigevent, event);
event.sigev_notify = SIGEV_SIGNAL;
event.sigev_signo = SIG_TIMER_EXPIRATION;
if (timer_create(CLOCK_TYPE, &event, &timer) != 0)
perror("timer_create");
sigset_t pending;
struct timespec H = get_time_stamp();
puts("SLEEPING 1 SECOND..."); sleep(1);
/* H is now 1 second in the past. */
get_time_stamp();
ZERO(struct itimerspec, spec);
spec.it_value = H;
if (timer_settime(timer, TIMER_ABSTIME, &spec, NULL) != 0)
perror("timer_settime");
if (sigpending(&pending) != 0) perror("sigpending");
int res=sigismember(&pending, SIG_TIMER_EXPIRATION);
if (res < 0) perror("sigismember");
else if (res) puts("TIMER HAS ALREADY FIRED.");
struct timespec H1 = get_time_stamp();
sigwaitinfo(&set, NULL);
struct timespec H2 = get_time_stamp();
int nsdiff = (H2.tv_sec-H1.tv_sec)*1000000000 + (H2.tv_nsec-H1.tv_nsec);
printf("nsdiff=%d ns i.e. %d ms\n", nsdiff, nsdiff/1000000);
return 0;
}
Thanks for reading this far!
Regards.
| |
|
| Spoon wrote:
> I'm still playing with the POSIX timers API. My platform is x86 running
> Linux 2.6.16.28 patched with the high-resolution timer subsystem.
>
> http://www.tglx.de/hrtimers.html
> http://www.tglx.de/projects/hrtimer...6.16-hrt6.patch
>
> I'm seeing unexpected behavior from timer_settime().
>
> int timer_settime(timer_t timerid, int flags,
> const struct itimerspec *value, struct itimerspec *ovalue);
>
> timer_settime() is used to arm a timer. If the TIMER_ABSTIME flag is
> set, then the timer should fire when the appropriate clock reaches the
> date specified by value. If that date is in the past, the timer should
> fire immediately.
>
> SUSv2 states:
>
> "If the flag TIMER_ABSTIME is set in the argument flags, timer_settime()
> behaves as if the time until next expiration is set to be equal to the
> difference between the absolute time specified by the it_value member of
> value and the current value of the clock associated with timerid. That
> is, the timer expires when the clock reaches the value specified by the
> it_value member of value. If the specified time has already passed, the
> function succeeds and the expiration notification is made."
>
> http://www.opengroup.org/onlinepubs...getoverrun.html
The Open Group Base Specifications Issue 6 is more recent.
http://www.opengroup.org/onlinepubs...getoverrun.html
"If the flag TIMER_ABSTIME is set in the argument flags, timer_settime()
shall behave as if the time until next expiration is set to be equal to
the difference between the absolute time specified by the it_value
member of value and the current value of the clock associated with
timerid. That is, the timer shall expire when the clock reaches the
value specified by the it_value member of value. If the specified time
has already passed, the function shall succeed and the expiration
notification shall be made."
| |
|
| Spoon wrote:
> I'm still playing with the POSIX timers API. My platform is x86 running
> Linux 2.6.16.28 patched with the high-resolution timer subsystem.
>
> http://www.tglx.de/hrtimers.html
> http://www.tglx.de/projects/hrtimer...6.16-hrt6.patch
>
> I'm seeing unexpected behavior from timer_settime().
>
> int timer_settime(timer_t timerid, int flags,
> const struct itimerspec *value, struct itimerspec *ovalue);
>
> timer_settime() is used to arm a timer. If the TIMER_ABSTIME flag is
> set, then the timer should fire when the appropriate clock reaches the
> date specified by value. If that date is in the past, the timer should
> fire immediately.
>
> In my tests, when timer_settime is called with an expiration date in the
> past, the timer takes a *LONG* time to fire.
I'd be interested to see the output of the program I provided in the
original message when run on different platforms.
e.g. x86/Solaris, SPARC/Solaris, SPARC/Linux.
As a reference, on an x86/Linux (2.6.16.28-hrt) box, I get:
# ./a.out
RESOLUTION=800 ns
NOW=8663.440797657
SLEEPING 1 SECOND...
NOW=8664.440831177
NOW=8664.440868945
NOW=8664.474870432
nsdiff=34001487 ns i.e. 34 ms
Regards.
| |
|
| Spoon wrote:
>
> I'd be interested to see the output of the program I provided in the
> original message when run on different platforms.
>
> e.g. x86/Solaris, SPARC/Solaris, SPARC/Linux.
>
> As a reference, on an x86/Linux (2.6.16.28-hrt) box, I get:
>
> # ./a.out
> RESOLUTION=800 ns
> NOW=8663.440797657
> SLEEPING 1 SECOND...
> NOW=8664.440831177
> NOW=8664.440868945
> NOW=8664.474870432
> nsdiff=34001487 ns i.e. 34 ms
and on an x86/Linux (2.6.18.1-hrt) box
# ./a.out
RESOLUTION=1 ns
NOW=506.971981147
SLEEPING 1 SECOND...
NOW=507.972013833
NOW=507.972047636
NOW=507.972161617
nsdiff=113981 ns i.e. 0 ms
In other words, the problem is less severe, but still present.
|
|
|
|
|