9.3 POSIX:XSI Interval Timers

Team-FLY

A timer generates a notification after a specified amount of time has elapsed. In contrast to a clock, which increments to track the passage of time, a timer usually decrements its value and generates a signal when the value becomes zero. A computer system typically has a small number of hardware interval timers, and the operating system implements multiple software timers by using these hardware timers.

Operating systems use interval timers in many ways. An interval timer can cause a periodic interrupt, triggering the operating system to increment a counter. This counter can keep the time since the operating system was booted . UNIX systems traditionally keep the time of day as the number of seconds since January 1, 1970. If an underlying interval timer generates an interrupt after 100 microseconds and is restarted each time it expires , the timer interrupt service routine can keep a local counter to measure the number of seconds since January 1, 1970, by incrementing this local counter after each 10,000 expirations of the interval timer.

Program 9.6 nanotest.c

A function that tests the resolution of nanosleep .

 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/time.h> #define COUNT 100 #define D_BILLION 1000000000.0 #define D_MILLION 1000000.0 #define MILLION 1000000L #define NANOSECONDS 1000 int main(void) {    int i;    struct timespec slptm;    long tdif;    struct timeval tend, tstart;    slptm.tv_sec = 0;    slptm.tv_nsec = NANOSECONDS;    if (gettimeofday(&tstart, NULL) == -1) {       fprintf(stderr, "Failed to get start time\n");       return 1;    }    for (i = 0; i < COUNT; i++)       if (nanosleep(&slptm, NULL) == -1) {          perror("Failed to nanosleep");          return 1;       }    if (gettimeofday(&tend, NULL) == -1) {       fprintf(stderr,"Failed to get end time\n");       return 1;    }    tdif = MILLION*(tend.tv_sec - tstart.tv_sec) +                    tend.tv_usec - tstart.tv_usec;    printf("%d nanosleeps of %d nanoseconds\n", COUNT, NANOSECONDS);    printf("Should take %11d microseconds or %f seconds\n",              NANOSECONDS*COUNT/1000, NANOSECONDS*COUNT/D_BILLION);    printf("Actually took %11ld microseconds or %f seconds\n", tdif,              tdif/D_MILLION);    printf("Number of seconds per nanosleep was %f\n",              (tdif/(double)COUNT)/MILLION);    printf("Number of seconds per nanosleep should be %f\n,              NANOSECONDS/D_BILLION);    return 0; } 

Time-sharing operating systems can also use interval timers for process scheduling. When the operating system schedules a process, it starts an interval timer for a time interval called the scheduling quantum . If this timer expires and the process is still executing, the scheduler moves the process to a ready queue so that another process can execute. Multiprocessor systems need one of these interval timers for each processor.

Most scheduling algorithms have a mechanism for raising the priority of processes that have been waiting a long time to execute. The scheduler might use an interval timer for priority management. Every time the timer expires, the scheduler raises the priority of the processes that have not executed.

The interval timers of the POSIX:XSI Extension use a struct itimerval structure that contains the following members .

 struct timeval it_value;    /* time until next expiration */ struct timeval it_interval; /* value to reload into the timer */ 

Here it_value holds the time remaining before the timer expires, and it_interval holds the time interval to be used for resetting the timer after it expires. Recall that a struct timeval structure has fields for seconds and microseconds.

A conforming POSIX:XSI implementation must provide each process with the following three user interval timers.

ITIMER_REAL:

decrements in real time and generates a SIGALRM signal when it expires.

ITIMER_VIRTUAL:

decrements in virtual time (time used by the process) and generates a SIGVTALRM signal when it expires.

ITIMER_PROF:

decrements in virtual time and system time for the process and generates a SIGPROF signal when it expires.

POSIX provides the getitimer function for retrieving the current time interval and the setitimer function for starting and stopping a user interval timer. The which parameter specifies the timer (i.e., ITIMER_REAL , ITIMER_VIRTUAL or ITIMER_PROF) . The getitimer function stores the current value of the time for timer which in the location pointed to by value . The setitimer function sets the timer specified by which to the value pointed to by value . If ovalue is not NULL , setitimer 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 .

  SYNOPSIS  #include <sys/time.h>    int getitimer(int which, struct itimerval *value);    int setitimer(int which, const struct itimerval *restrict value,                             struct itimerval *restrict ovalue);  POSIX:XSI  

If successful, these functions return 0. If unsuccessful , they return “1 and set errno . The setitimer function sets errno to EINVAL if the number of microseconds in value is not in the range [0, 10 6 ).

If the it_interval member of *value is not 0, the timer restarts with this value when it expires. If the it_interval of *value is 0, the timer does not restart after it expires. If the it_value of *value is 0, setitimer stops the timer if it is running.

Program 9.7 uses an ITIMER_PROF timer to print out an asterisk for each two seconds of CPU time used. The program first calls setupinterrupt to install myhandler as the signal handler for SIGPROF . Then, the program calls setupitimer to set up a periodic timer, using ITIMER_PROF , that expires every 2 seconds. The ITIMER_PROF timer generates a SIGPROF signal after every two seconds of CPU time used by the process. The process catches the SIGPROF signal and handles it with myhandler . This handler function outputs an asterisk to standard error.

Program 9.7 periodicasterisk.c

A program that prints an asterisk for each two seconds of CPU time used .

 #include <errno.h> #include <signal.h> #include <stdio.h> #include <unistd.h> #include <sys/time.h> /* ARGSUSED */ static void myhandler(int s) {    char aster = '*';    int errsave;    errsave = errno;    write(STDERR_FILENO, &aster, 1);    errno = errsave; } static int setupinterrupt(void) {              /* set up myhandler for SIGPROF */    struct sigaction act;    act.sa_handler = myhandler;    act.sa_flags = 0;    return (sigemptyset(&act.sa_mask)  sigaction(SIGPROF, &act, NULL)); } static int setupitimer(void) {    /* set ITIMER_PROF for 2-second intervals */    struct itimerval value;    value.it_interval.tv_sec = 2;    value.it_interval.tv_usec = 0;    value.it_value = value.it_interval;    return (setitimer(ITIMER_PROF, &value, NULL)); } int main(void) {    if (setupinterrupt() == -1) {       perror("Failed to set up handler for SIGPROF");       return 1;    }    if (setupitimer() == -1) {       perror("Failed to set up the ITIMER_PROF interval timer");       return 1;    }    for ( ; ; );                        /* execute rest of main program here */ } 
Exercise 9.11

Write a program that sets ITIMER_REAL to expire in two seconds and then sleeps for ten seconds. How long does it take for the program to terminate? Why?

Answer:

POSIX states that the interaction between setitimer and any of alarm , sleep or usleep is unspecified, so we can't predict how long it will take. Avoid this combination in your programs by using nanosleep instead of sleep .

Exercise 9.12

What is wrong with the following code, which should print out the number of seconds remaining on the ITIMER_VIRTUAL interval timer?

 struct itimerval *value; getitimer(ITIMER_VIRTUAL, value); fprintf(stderr, "Time left is %ld seconds\n", value->it_value.tv_sec); 

Answer:

Although the variable value is declared as a pointer to a struct itimerval structure, it does not point to anything. That is, there is no declaration of an actual struct itimerval structure that value represents.

Program 9.8 uses the interval timer ITIMER_VIRTUAL to measure the execution time of function_to_time . This example, unlike Program 9.1, uses virtual time. Remember that the value returned by getitimer is the time remaining, so the quantity is decreasing .

Exercise 9.13

How can you modify Program 9.8 to compensate for the overhead of calling setitimer and getitimer ?

Answer:

Call the setitimer and getitimer pair with no intervening statements and use the time difference as an estimate of the timing overhead.

Exercise 9.14

What happens if we replace the final return in Program 9.8 with the infinite loop for( ; ; ); ?

Answer:

After using one million seconds of virtual time, the program receives a SIGVTALRM signal and terminates. One million seconds is approximately 12 days.

Program 9.8 xsitimer.c

A program that uses a POSIX:XSI interval timer to measure the execution time of a function .

 #include <stdio.h> #include <sys/time.h> #define MILLION 1000000L void function_to_time(void); int main(void) {    long diftime;    struct itimerval ovalue, value;    ovalue.it_interval.tv_sec = 0;    ovalue.it_interval.tv_usec = 0;    ovalue.it_value.tv_sec = MILLION;                    /* a large number */    ovalue.it_value.tv_usec = 0;    if (setitimer(ITIMER_VIRTUAL, &ovalue, NULL) == -1) {       perror("Failed to set virtual timer");       return 1;    }    function_to_time();                            /* timed code goes here */    if (getitimer(ITIMER_VIRTUAL, &value) == -1) {       perror("Failed to get virtual timer");       return 1;    }    diftime = MILLION*(ovalue.it_value.tv_sec - value.it_value.tv_sec) +                ovalue.it_value.tv_usec - value.it_value.tv_usec;    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