Posix Timer periodically skips ahead half of its period
I have a task linked to a Posix Timer (timer_create()) that executes every 20 ms/50 Hz. Works fine for the most part, except every 334.5 seconds (approx.) the timer executes 10 ms early for the one cycle. For the next 334.5-ish seconds the intervals are all 20 ms again.
I've included the relevant code for configuring the timer. The application runs on a Gumstix Verdex Pro XL6P with Gumstix's default version of Linux. I also have it scheduled with FIFO scheduling algorithm.
My gut says this is a integer overflow issue. Maybe there's something else using the same signal? I've consistently been able to reproduce the skip, across executions and sessions on the board.
The issue's not a show stopper, but I would really like to understand why this is happening.
Here's the code for configuring the timer:
//------------------------------------------------------------------------------
// Create a timer which fires at the specified time and calls a timer event
// handler.
//
// handler : function to be called when the timer expires
// us : number of microseconds to add to timer
// ms : number of milliseconds to add to timer
// sec : number of seconds to add to timer
//开发者_如何学Go------------------------------------------------------------------------------
void createTimer(void (*handler)(void), uint32 us, uint32 ms, uint32 sec)
{
struct sigaction sigact;
struct sigevent sigev;
timer_t timerid;
struct itimerspec itval;
struct itimerspec oitval;
timer_info_t* newTimer = NULL;
// Initialize signalNum.
if (timers == NULL)
signalNum = SIGRTMAX;
if (signalNum < SIGRTMIN)
exitWithError("no avaiable signals, unable to create timers");
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_SIGINFO;
sigact.sa_sigaction = signalHandler;
// Set up sigaction to catch signal
if (sigaction(signalNum, &sigact, NULL) == -1)
exitWithError("sigaction() failed, unabled to creat timers");
// Create the POSIX timer to generate signo
sigev.sigev_notify = SIGEV_SIGNAL;
sigev.sigev_signo = signalNum;
sigev.sigev_value.sival_ptr = &timerid;
long ret = timer_create(CLOCK_REALTIME, &sigev, &timerid);
if (ret == 0)
{
// Prevent overflow in calculation of nsec below.
if (ms >= 1000)
{
sec += (ms / 1000);
ms = ms % 1000;
}
itval.it_value.tv_sec = sec;
itval.it_value.tv_nsec = (long)(us * 1000L) + (long)(ms * 1000L * 1000L);
// Configure it as a repeat timer.
itval.it_interval.tv_sec = itval.it_value.tv_sec;
itval.it_interval.tv_nsec = itval.it_value.tv_nsec;
if (timer_settime(timerid, 0, &itval, &oitval) != 0)
exitWithError("time_settime() error!");
}
else
exitWithError("timer_create() error!");
newTimer = (timer_info_t*)malloc(sizeof(timer_info_t));
newTimer->timer = timerid;
newTimer->handler = handler;
newTimer->sigNum = signalNum;
newTimer->next = NULL;
// Check to see if this is the first time through.
if (timers == NULL)
{
timers = newTimer;
atexit(deleteTimers);
}
else
lastTimer->next = newTimer;
lastTimer = newTimer;
signalNum--;
}
Thanks in advance.
My guess is that you're using ntp, and that it's slewing the time at those intervals. You could try to use CLOCK_MONOTONIC
instead, but according to http://juliusdavies.ca/posix_clocks/clock_realtime_linux_faq.html it might also be affected.
精彩评论