POSIX Interval Timers
** Note: I did not write this. I rescued this from the google cache before it expired so someone else could benefit from this useful bit of POSIX knowledge.
The 1170 specification timers do not provide sufficient flexiblity to deal with real time tasks. To be useful in a realtime programming environment, we need the following:
- support of additional clocks beyond ITIMER_REAL, ITIMER_VIRTUAL, and ITIMER_PROF.
- allowance for greater time resolution (i.e. nanosecond resolution)
- ability to determine timer overruns.
- ability to use something other than SIGALRM to indicate timer expiration.
As a result, POSIX.1b defines a new set of timer functions that meet the additional requirements stated above. Note that in compiling POSIX.1b programs, the compiler options must include -lposix4. (POSIX.4 is an older name for the POSIX.1b standard).
In POSIX.1, each process has only three timers. In POSIX.1b, there are a small number of clocks such as CLOCK_REALTIME and a process can create many independent timers based on these hardware clocks.
POSIX.1b timers are based on the structure itimerspec which has the following members
struct timespec it_interval; /*timer period*/ struct timespec it_value; /*timer expiration*/
In addition to this, POSIX.1b realtime extensions define a fine-grained facility for telling time. The structure timespec provides the additional resolution and has the following members
struct timespec{
time_t tv_sec; /*seconds*/
long tv_nsec; /*nanoseconds*/
};
A process can create specific timers by using the system call timer_create. The timers are not inherited on fork. The prototype for the function call is
#include
#include
int timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid);
struct sigevent{
int sigev_notify; /*notification type*/
int sigev_signo; /*signal number*/
union sigval sigev_value; /*signal value*/
};
union sigval{
int sival_int; /*integer value*/
void *sival_ptr; /*pointer value*/
};
The clock_id specifies which clock the timer is based on and *timerid holds the ID of the created timer. The call timer_create returns 0 on success. It returns -1 and sets errno on failure.
The members of the sigevent structure and the sigval union define what “event” occurs upon timer expiration. The *evp parameter specifies which signal should be sent to the process when the timer expires. If evp is NULL, the timer generates the default. For CLOCK_REALTIME the default signal is SIGALRM. In order for the timer expiration to generate a different signal, the structure member evp->sigev_signo must be set to the desired signal number. The evp->sigev_notify member indicates the action to be taken when the timer expires. Normally, this member is SIGEV_SIGNAL to indicate that the signal is generated. The program can prevent the timer expiration from generating a signal by setting evp->sigev_notify to SIGEV_NONE.
If several timers generate the same signal, the handler can use evp->sigev_value to distinguish which timer generated the signal. In order to do this, the program must use the SA_SIGINFO flag in the sa_flags member of the structure sigaction when it installs the handler for the signal.
The following three functions manipulate the process’ POSIX.1b timers.
#include int timer_settime(timer_t timerid, int flags); const struct itimerspec *value, struct itimerspec *ovalue); int timer_gettime(timer_t timerid, struct itimerspec *value); int timer_getoverrun(timer_t timerid);
The timer_settime function starts or stops a timer that was created by calling timer_create. The flags parameter indicates whether the timer uses relative or absolute time. Relative time is similar to Spec 1170 timers while absolute time allows for greater accuracy and control of timer drift (this is what we use for realtime programming) The last two parameters have the same meaning as for setitimer. The timer_settime and timer_gettime functions return 0 on success while timer_getoverrun returns the number of timer overruns. On failure all of these routines return -1 and set errno.
The following code segment shows an example of the simplest and most common way in which POSIX.1b facilities are used.
#define _POSIX_C_SOURCE 199506L
#include
#include
#include
#include
#define OUR_CLOCK CLOCK_REALTIME
char *prog_name;
void timer_intr(int sig, siginfo_t *extra, void *cruft)
{
int noverflow;
if(noverflow=timer_getoverrun(*(timer_t *)extra->si_value.sival_ptr)) {
/*timer has overflowed — error !*/
}
return;
} timer_t mytimer;
main(int argc, char **argv){
int c;
struct itimerspec i;
struct timespec resolution;
struct sigaction sa;
sigset_t allsigs;
struct sigevent timer_event;
prog_name=argv[0];
sigemptyset(&sa.sa_mask);
sa.sa_flags=SA_SIGINFO; /*real-time signal*/
sa.sa_sigaction=timer_intr; /*pointer to action*/
if(sigaction(SIGRTMIN, &sa, NULL) < 0) {
perror(“sigaction error”);
exit(1);
}
/*
* first determine whether the desired clock exists
*/
if (clock_getres(OUR_CLOCK, &resolution) < 0){
perror(“clock_getres error”);
exit(1);
}
printf(“clock resolution %d sec %d nsec n”, resolution.tv_sec, resolution.tv_nsec);
/*
* create a timer based upon the CLOCK_REALTIME clock
*/
i.it_interval.tv_sec=0;
/* set resolution to one-tenth of the maximum allowed*/
i.it_interval.tv_nsec=resolution.tv_nsec*10;
i.it_value=i.it_interval;
/*
* this describes the asynchronous notification to be posted
* upon this timer’s expiration:
*
* - use signals
* - send SIGRTMIN
* - send extra data consisting of a pointer back to the timer ID
* cannot pass the timer ID itself because we haven’t created it
* yet.
*/
timer_event.sigev_notify=SIGEV_SIGNAL;
timer_event.sigev_signo= SIGRTMIN;
timer_event.sigev_value.sival_ptr = (void *)&mytimer;
if (timer_create(OUR_CLOCK, &timer_event, &mytimer) < 0) {
perror(“timer create error”);
exit(1);
}
/* relative timer, go off at the end of the interval*/
if(timer_settime(mytimer, 0 , &i, NULL) < 0) {
perror(“settimer”);
exit(3);
}
sigemptyset(&allsigs);
while(1) {
sigsuspend(&allsigs);
}
exit(4);