How to force C timer to expire at specific system time in Linux

I was trying to create a timer that depends on the system clock. This means that if you change the system time, this should also affect the expiration of this timer. So I thought that creating a timer based on CLOCK_REALTIME should do the trick. But when this timer was armed before 60 seconds had elapsed and when I increased the system clock by 32 seconds (using the date command) the timer expired in exactly 60 seconds. It did not expire 32 seconds early.

So, I calculated the elapsed time for the CLOCK_REALTIME and CLOCK_MONOTONIC clocks between the expiration of the two timers. It showed 92 seconds for CLOCK_REALTIME and 60 seconds for CLOCK_MONOTONIC, which made me wonder if a timer based on CLOCK_REALTIME was not looking for system clock changes. Can anyone explain this behavior?

#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <string.h>
#include <sys/time.h>

timer_t timerID;
struct timespec rt1, rt2, mt1, mt2;

void TimerCalback()
{
  clock_gettime(CLOCK_REALTIME, &rt1);
  clock_gettime(CLOCK_MONOTONIC, &mt1);
  printf("%lu sec elapsed for CLOCK_REALTIME\n", rt1.tv_sec - rt2.tv_sec);
  printf("%lu sec elapsed for CLOCK_MONOTONIC\n", mt1.tv_sec - mt2.tv_sec);

  rt2 = rt1;
  mt2 = mt1;

  time_t rawtime;
  struct tm * timeinfo;
  time ( &rawtime );
  timeinfo = localtime ( &rawtime );
  printf("REALTIME Timer Expired at %s\n", asctime (timeinfo));
}

void CreateTimer()
{
  struct sigaction sa;
  sa.sa_flags     = SA_SIGINFO;
  sa.sa_sigaction = TimerCalback;

  sigemptyset(&sa.sa_mask);
  sigaction(SIGRTMIN, &sa, NULL);
  struct sigevent te;
  memset(&te,0,sizeof(struct sigevent));

  te.sigev_notify          = SIGEV_SIGNAL;
  te.sigev_signo           = SIGRTMIN;
  te.sigev_value.sival_ptr = &timerID;
  timer_create(CLOCK_REALTIME, &te, &timerID);

  struct itimerspec its;
  its.it_value.tv_sec     = 1;
  its.it_value.tv_nsec    = 0;

  its.it_interval.tv_sec  = 60;
  its.it_interval.tv_nsec = 0;

  timer_settime(timerID, 0, &its, NULL);
}

void main()
{
  CreateTimer();
  while(1)
  {
    usleep(1);
  }
}

      

And I got this conclusion. After the first expiration, I switched to the system clock.

$ ./realtimeTimer
1407240463 sec elapsed for CLOCK_REALTIME
17747 sec elapsed for CLOCK_MONOTONIC
REALTIME Timer Expired at Tue Aug  5 17:37:43 2014

92 sec elapsed for CLOCK_REALTIME
60 sec elapsed for CLOCK_MONOTONIC
REALTIME Timer Expired at Tue Aug  5 17:39:15 2014  

      

Later on searching the internet I came across this manual page which says

All implementations support a system-wide real-time clock, which is identified by CLOCK_REALTIME. Its time is seconds and nanoseconds from the epoch. When the time changes, the timers for the relative interval are not affected , but the timers for the absolute time are affected.

Could this be the reason for this behavior?
What am I doing wrong / missing here? Is there a way to make the timer expire at a specific system time?

+3


source to share


2 answers


The same rule is found in the manpage for timer_settime

, with some additional explanation:

By default, the initial expiry time specified in is         new_value->it_value

interpreted relative to the current time on the timer clock during the call. This can be changed by specifying TIMER_ABSTIME in the flags, in which case new_value-> it_value is interpreted as the absolute value measured on the timer; that is, the timer will expire when the clock reaches the specified value new_value->it_value

. If the specified absolute time has already elapsed, then the timer will expire immediately and the count overflow (see timer_getoverrun

(2)) will be set correctly.

If the CLOCK_REALTIME value is adjusted when the absolute timer is based on the fact that the clock is armed, then the expiration timer will be adjusted accordingly. Adjustments         Clock CLOCK_REALTIME not affect the relative timers based on this clock.

Yes, you are setting a relative timer and why it ignores the system time setting.



You can try this:

struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);

struct itimerspec its;
its.it_value.tv_sec     = ts.tv_sec + 1;
its.it_value.tv_nsec    = ts.tv_nsec;
its.it_interval.tv_sec  = 60;
its.it_interval.tv_nsec = 0;
timer_settime(timerID, TIMER_ABSTIME, &its, NULL);

      

+2


source


Try the following:



struct timeval tv;
gettimeofday(&tv, NULL);

struct itimerspec its;
its.it_value.tv_sec     = 1;
its.it_value.tv_nsec    = 0;
its.it_interval.tv_sec  = tv_sec + 60;
its.it_interval.tv_nsec = tv_nsec;
timer_settime(timerID, TIMER_ABSTIME, &its, NULL);

      

0


source







All Articles