Interval Timers in Unix/Linux

Linux provides each process with three different kinds of interval timers, which can be used as virtual clocks for process timing. Interval timers are created by the setitimer() system call. The getitimer() system call returns the status of an interval timer.

int getitimer(int which, struct itimerval *curr_value);

int setitimer(int which, const struct itimerval *new_value,

struct itimerval *old_value);

Each interval timer operates in a distinct time domain specified by the parameter which. When an interval timer expires, a signal is sent to the process, and the timer is reset to the specified interval value (if nonzero). A signal is a number (1 to 31) sent to a process for the process to handle. Signals and signal processing will be covered in Chap. 6. For the time being, the reader may regard timer related signals as interrupts to a process, just like physical timer interrupts to a CPU. The 3 kinds of interval timers are

  1.  ITIMER_REAL: decrement in real time, generate a SIGALRM (14) signal upon expiration.
  2.  ITIMER_VIRTUAL: decrement only when the process is executing in user mode, generate a SIGVTALRM (26) signal upon expiration.
  3.  ITIMER_PROF: decrement when the process is executing in user mode and also in system (kernel) mode. Coupled with ITIMER_VIRTUAL, this interval timer is usually used to profile the time spent by the application in user and kernel modes. It generates a SIGPROF (27) signal upon expiration.

Interval timer values are defined by the following structures (in <sys/time.h>):

The function getitimer() fills the structure pointed to by curr_value with the current value i.e., the time remaining until the next expiration, of the timer specified by which (one of ITIMER_REAL, ITIMER_VIRTUAL, or ITIMER_PROF). The subfields of the field it_value are set to the amount of time remaining on the timer, or zero if the timer is disabled. The it_interval field is set to the timer interval (period); a value of zero returned in (both subfields of) this field indicates that this is a single­shot timer.

The function setitimer() sets the specified timer to the value in new_value. If old_value is non-NULL, the old value of the timer,i.e. the same information as returned by getitimer(), is stored there.

Periodic timers decrement from it_value to zero, generate a signal, and reset to it_interval. A timer which is set to zero (it_value is zero or the timer expires and it_interval is zero) stops the timer. Both tv_sec and tv_usec are significant in determining the duration of a timer. We demonstrate process interval timers by examples.

Example 5.4 This example shows how to set a VIRTUAL mode interval timer, which decrements its count only when the process is executing in user mode. The timer is set to start after an initial count of 100 msec has expired. Then it runs with a period of 1 second. When the timer count decrements to zero, it generates a SIGVTALRM(26) signal to the process. If the process did not install a catcher for the signal, it will handle the signal by default, which is to terminate. In that case, the process will terminate with a signal number 26. If the process has installed a signal catcher, the Linux kernel will let the process execute the signal catcher to handle the signal in user mode. Before starting the interval time, the program installs a signal catcher for the SIGVTALRM signal by

void timer_handler(int sig){ . . .   .}

signal(SIGALRM, timer handler)

After installing the signal catcher, the program starts the timer and then executes in a while(1) loop. While executing in the loop, every hardware interrupt, e.g. interrupts from hardware timers, causes the CPU, hence the process executing on the CPU, to enter the Linux kernel to handle the interrupt. Whenever a process is in kernel mode, it checks for pending signals. If there is a pending signal, it tries to handle the signal before returning to user mode. In this case, a SIGVTALRM signal would cause the process to execute the signal catcher in user mode. Since the interval timer is programmed to generate a signal every second, the process would execute timer_handler() once every second, making the printed message to appear once per second like a pulsar. The signal catcher function, timer_handler(), counts the number of times the interval timer has expired. When the count reaches a prescribed value, e.g. 8, it cancels the interval timer by setitimer() with a timer value 0. Although the timer has stopped, the process is still executing in an infinite while(1) loop. In this case, entering a Control-C key from the keyboard would cause the process to terminate with a SIGINT(2) signal. Details of signals and signal handling will be covered in Chap. 6. The following shows the setitimer.c program code of Example 5.5.

/*********** setitimer.c file *********/

#include <signal.h>

#include <stdio.h>

#include <sys/time.h> int count = 0; struct itimerval t;

void timer_handler(int sig)

{

printf(“timer_handler: signal=%d count=%d\n”, sig, ++count);

if (count>=8){

printf(“cancel timer\n”);

t.it_value.tv_sec = 0;

t.it_value.tv_usec = 0;

setitimer(ITIMER_VIRTUAL, &t, NULL);

}

}

int main()

{

struct itimerval timer;

// Install timer_handler as SIGVTALRM signal handler

signal(SIGVTALRM, timer handler);

// Configure the timer to expire after 100 msec

timer.it_value.tv_sec = 0;

timer.it_value.tv_usec = 100000; // 100000 nsec

// and every 1 sec afterward

timer.it_interval.tv_sec = 1;

timer.it_interval.tv_usec = 0;

// Start a VIRTUAL itimer

setitimer(ITIMERVIRTUAL, &timer, NULL);

printf(“looping: enter Control-C to terminate\n”);

while(1);

}

Figure 5.1 show the outputs of running the setitimer program

Fig. 5.1 Outputs of setitimer program

Source: Wang K.C. (2018), Systems Programming in Unix/Linux, Springer; 1st ed. 2018 edition.

Leave a Reply

Your email address will not be published. Required fields are marked *