9.5 POSIX:TMR Interval Timers

Team-FLY

The interval timer facility of the POSIX:XSI Extension gives each process a small fixed number of timers, one of each of the types ITIMER_REAL , ITIMER_VIRTUAL , ITIMER_PROF and so on. The POSIX:TMR Extension takes an alternative approach in which there are a small number of clocks, such as CLOCK_REALTIME , and a process can create many independent timers for each clock.

POSIX:TMR timers are based on the struct itimerspec structure, which has the following members .

 struct timespec it_interval;  /* timer period */ struct timespec it_value;     /* timer expiration */ 

As with POSIX:XSI timers, the it_interval is the time used for resetting the timer after it expires . The it_value member holds the time remaining before expiration. The struct timespec structure has the potential of offering better resolution than struct timeval since its fields measure seconds and nanoseconds rather than seconds and microseconds.

A process can create specific timers by calling timer_create . The timers are per-process timers that are not inherited on fork . The clock_id parameter of timer_create specifies which clock the timer is based on, and *timerid holds the ID of the created timer. The evp parameter specifies the asynchronous notification to occur when the timer expires. The timer_create function creates the timer and puts its ID in the location pointed to by timerid .

  SYNOPSIS  #include <signal.h>   #include <time.h>   int timer_create(clockid_t clock_id, struct sigevent *restrict evp,                    timer_t *restrict 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 */   };  POSIX:TMR  

If successful, timer_create returns 0. If unsuccessful , timer_create returns “1 and sets errno . The following table lists the mandatory errors for timer_create .

errno

cause

EAGAIN

system does not have resources to honor request, or calling process already has maximum number of timers allowed

EINVAL

specified clock ID is not defined

The members of the struct sigevent structure shown in the synopsis are required by the POSIX:TMR Extension. The standard does not prohibit an implementation from including additional members.

Example 9.16

The following code segment creates a POSIX:TMR timer based on the CLOCK_REALTIME .

 timer_t timerid; if (timer_create(CLOCK_REALTIME, NULL, &timerid) == -1)    perror("Failed to create a new timer); 

The *evp parameter of timer_create specifies which signal should be sent to the process when the timer expires. If evp is NULL , the timer generates the default signal when it expires. For CLOCK_REALTIME , the default signal is SIGALRM . For the timer expiration to generate a signal other than the default signal, the program must set evp->sigev_signo to the desired signal number. The evp->sigev_notify member of the struct sigevent structure specifies the action to be taken when the timer expires. Normally, this member is SIGEV_SIGNAL , which specifies that the timer expiration generates a signal. The program can prevent the timer expiration from generating a signal by setting the evp->sigev_notify member to SIGEV_NONE .

The timer_delete function deletes the POSIX:TMR timer with ID timerid .

  SYNOPSIS  #include <time.h>   int timer_delete(timer_t timerid);  POSIX:TMR  

If successful, timer_delete returns 0. If unsuccessful, timer_delete returns “1 and sets errno . The timer_delete function sets errno to EINVAL if timerid does not correspond to a valid timer.

Exercise 9.17

What happens if a program calls timer_delete when there are pending signals for timerid ?

Answer:

POSIX does not specify what happens to pending signals. You should not make any assumptions about their disposition when calling timer_delete .

If several timers generate the same signal, the handler can use evp->sigev_value to distinguish which timer generated the signal. To do this, the program must use the SA_SIGINFO flag in the sa_flags member of struct sigaction when it installs the handler for the signal. (See Program 9.13 for an example of how to do this.)

The following three functions manipulate the per-process POSIX:TMR timers. The timer_settime function starts or stops a timer that was created by timer_create . The flags parameter specifies whether the timer uses relative or absolute time. Relative time is similar to the scheme used by POSIX:XSI timers, whereas absolute time allows for greater accuracy and control of timer drift . Absolute time is further discussed in Section 9.6. The timer_settime function sets the timer specified by timerid to the value pointed to by value . If ovalue is not NULL , timer_settime places the previous value of the timer in the location pointed to by ovalue . If the timer was running, the it_value member of *ovalue is nonzero and contains the time remaining before the timer would have expired . Use timer_gettime like getitimer to get the time remaining on an active timer.

It is possible for a timer to expire while a signal is still pending from a previous expiration of the same timer. In this case, one of the signals generated may be lost. This is called timer overrun . A program can determine the number of such overruns for a particular timer by calling timer_getoverrun . Timer overruns occur only for signals generated by the same timer. Signals generated by multiple timers, even timers using the same clock and signal, are queued and not lost.

  SYNOPSIS  #include <time.h>   int timer_getoverrun(timer_t timerid);   int timer_gettime(timer_t timerid, struct itimerspec *value);   int timer_settime(timer_t timerid, int flags,        const struct itimerspec *value, struct itimerspec *ovalue);  POSIX:TMR  

If successful, the timer_settime and timer_gettime functions return 0, and the timer_getoverrun function returns the number of timer overruns. If unsuccessful, all three functions return “1 and set errno . All three functions set errno to EINVAL when timerid does not correspond to a valid POSIX:TMR timer. The timer_settime function also sets errno to EINVAL when the nanosecond field of value is not in the range [0, 10 9 ).

Program 9.11 shows how to create a timer that generates periodic interrupts. It generates a SIGALRM interrupt every two seconds of real time.

Exercise 9.18

Why didn't we use strlen in Program 9.11 to find the length of the message?

Answer:

The strlen function is not guaranteed to be async-signal safe.

Exercise 9.19

Program 9.11 uses pause in an infinite loop at the end of the program but Program 9.7 does not. What would happen if we used pause in Program 9.7?

Answer:

Nothing! There is no output.Program 9.7 measures virtual time and the process is not using any virtual time when it is suspended . Program 9.11 uses real time.

Program 9.11 periodicmessage.c

A program that displays a message every two seconds .

 #include <errno.h> #include <signal.h> #include <stdio.h> #include <time.h> #include <unistd.h> #define BILLION 1000000000L #define TIMER_MSG "Received Timer Interrupt\n" /* ARGSUSED */ static void interrupt(int signo, siginfo_t *info, void *context) {    int errsave;    errsave = errno;    write(STDOUT_FILENO, TIMER_MSG, sizeof(TIMER_MSG) - 1);    errno = errsave; } static int setinterrupt() {    struct sigaction act;    act.sa_flags = SA_SIGINFO;    act.sa_sigaction = interrupt;    if ((sigemptyset(&act.sa_mask) == -1)         (sigaction(SIGALRM, &act, NULL) == -1))       return -1;    return 0; } static int setperiodic(double sec) {    timer_t timerid;    struct itimerspec value;    if (timer_create(CLOCK_REALTIME, NULL, &timerid) == -1)       return -1;    value.it_interval.tv_sec = (long)sec;    value.it_interval.tv_nsec = (sec - value.it_interval.tv_sec)*BILLION;    if (value.it_interval.tv_nsec >= BILLION) {       value.it_interval.tv_sec++;       value.it_interval.tv_nsec -= BILLION;    }    value.it_value = value.it_interval;    return timer_settime(timerid, 0, &value, NULL); } int main(void) {    if (setinterrupt() == -1) {       perror("Failed to setup SIGALRM handler");       return 1;    }    if (setperiodic(2.0) == -1) {       perror("Failed to setup periodic interrupt");       return 1;    }    for ( ; ; )       pause(); } 

Program 9.12 creates a POSIX:TMR timer to measure the running time of function_to_time . The program is similar to Program 9.8, but it uses real time rather than virtual time.

Program 9.12 tmrtimer.c

A program that uses a POSIX:TMR timer to measure the running time of a function .

 #include <stdio.h> #include <time.h> #define MILLION 1000000L #define THOUSAND 1000 void function_to_time(void); int main(void) {    long diftime;    struct itimerspec nvalue, ovalue;    timer_t timeid;    if (timer_create(CLOCK_REALTIME, NULL, &timeid) == -1) {       perror("Failed to create a timer based on CLOCK_REALTIME");       return 1;    }    ovalue.it_interval.tv_sec = 0;    ovalue.it_interval.tv_nsec = 0;    ovalue.it_value.tv_sec = MILLION;                /* a large number */    ovalue.it_value.tv_nsec = 0;    if (timer_settime(timeid, 0, &ovalue, NULL) == -1) {       perror("Failed to set interval timer");       return 1;    }    function_to_time();                        /* timed code goes here */    if (timer_gettime(timeid, &nvalue) == -1) {       perror("Failed to get interval timer value");       return 1;    }    diftime = MILLION*(ovalue.it_value.tv_sec - nvalue.it_value.tv_sec) +       (ovalue.it_value.tv_nsec - nvalue.it_value.tv_nsec)/THOUSAND;    printf("The function_to_time took %ld microseconds or %f seconds.\n",            diftime, diftime/(double)MILLION);    return 0; } 
Team-FLY


Unix Systems Programming
UNIX Systems Programming: Communication, Concurrency and Threads
ISBN: 0130424110
EAN: 2147483647
Year: 2003
Pages: 274

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net