Linux Timers & Sleeping

โฑ๏ธ Linux Timers & Sleeping
Chapter 23 | Part 1 of 9 โ€” Interval Timers: setitimer() & alarm()
๐Ÿ“ฆ Topic
setitimer()
๐Ÿ”” Signal
SIGALRM
๐Ÿ’ก Level
Intermediate

What is an Interval Timer?

An interval timer lets a process schedule a notification (signal) for itself at a future point in time, and optionally at repeated regular intervals after that.

Think of it like setting a recurring alarm on your phone โ€” you set it once, and it keeps ringing every N seconds until you cancel it.

Linux provides three types of interval timers via setitimer(), each counting time differently:

๐Ÿ• Three Types of Interval Timers
Timer Type What It Measures Signal Delivered Use Case
ITIMER_REAL Wall-clock (real) time SIGALRM Timeouts, scheduling
ITIMER_VIRTUAL User-mode CPU time only SIGVTALRM CPU usage limits
ITIMER_PROF User + kernel CPU time SIGPROF Profiling tools

โš™๏ธ How setitimer() Works โ€” Timer Lifecycle
๐Ÿ“ž

setitimer()
called

โ†’
โฌ‡๏ธ

Timer counts
down from
it_value โ†’ 0

โ†’
๐Ÿ””

Signal sent
(e.g. SIGALRM)

โ†’
๐Ÿ”„

If it_interval
โ‰  0, reload
& repeat

โ†’
๐Ÿ›‘

alarm(0)
to stop

๐Ÿ—‚๏ธ Key Data Structures
struct itimerval

struct itimerval {
  struct timeval it_interval;
  /* Repeat interval */
  struct timeval it_value;
  /* Time until expiry */
};
struct timeval

struct timeval {
  time_t      tv_sec;
  /* Seconds */
  suseconds_t tv_usec;
  /* Microseconds */
};
๐Ÿ’ก Rule: If it_interval is all zeros โ†’ one-shot timer. If non-zero โ†’ repeating timer reloaded after each expiry.

๐Ÿ“‹ Function Signatures
#include <sys/time.h>

/* Set or get interval timer */
int setitimer(int which,
              const struct itimerval *new_value,
              struct itimerval *old_value);
/* Returns 0 on success, -1 on error */

/* Get current timer state */
int getitimer(int which,
              struct itimerval *curr_value);
/* Returns 0 on success, -1 on error */

/* Simple one-shot real timer */
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
/* Returns seconds remaining from previous timer, or 0 */

๐Ÿ’ป Example 1: One-Shot Timer using alarm()

The simplest way to set a timer โ€” fire once after N seconds.

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

/* Signal handler for SIGALRM */
void alarm_handler(int sig) {
    printf("ALARM: Timer expired! (signal %d)\n", sig);
}

int main(void) {
    struct sigaction sa;

    /* Register SIGALRM handler */
    sa.sa_handler = alarm_handler;
    sa.sa_flags   = 0;
    sigemptyset(&sa.sa_mask);
    sigaction(SIGALRM, &sa, NULL);

    printf("Setting alarm for 3 seconds...\n");
    alarm(3);   /* Fire SIGALRM after 3 seconds */

    printf("Waiting (sleeping 10s, alarm will wake us)...\n");
    pause();    /* Suspend until any signal */

    printf("Back from pause(). Exiting.\n");
    return 0;
}

/* Output:
   Setting alarm for 3 seconds...
   Waiting (sleeping 10s, alarm will wake us)...
   ALARM: Timer expired! (signal 14)
   Back from pause(). Exiting.
*/
Compile & Run:
gcc alarm_demo.c -o alarm_demo && ./alarm_demo

๐Ÿ’ป Example 2: Repeating Timer using setitimer()

A periodic timer that fires every 1 second using ITIMER_REAL.

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

static volatile int count = 0;

void sigalrm_handler(int sig) {
    count++;
    printf("SIGALRM #%d received\n", count);
    if (count >= 5) {
        printf("Got 5 signals, stopping.\n");
        /* Disarm timer by setting all fields to 0 */
        struct itimerval stop = {0};
        setitimer(ITIMER_REAL, &stop, NULL);
    }
}

int main(void) {
    struct sigaction sa;
    struct itimerval timer;

    /* Setup handler */
    sa.sa_handler = sigalrm_handler;
    sa.sa_flags   = 0;
    sigemptyset(&sa.sa_mask);
    sigaction(SIGALRM, &sa, NULL);

    /* First expiry: 1 second */
    timer.it_value.tv_sec  = 1;
    timer.it_value.tv_usec = 0;

    /* Repeat interval: every 1 second */
    timer.it_interval.tv_sec  = 1;
    timer.it_interval.tv_usec = 0;

    printf("Starting repeating timer (fires every 1s)...\n");
    setitimer(ITIMER_REAL, &timer, NULL);

    /* Wait for signals */
    while (count < 5)
        pause();

    printf("Done.\n");
    return 0;
}

/* Output:
   Starting repeating timer (fires every 1s)...
   SIGALRM #1 received
   SIGALRM #2 received
   SIGALRM #3 received
   SIGALRM #4 received
   SIGALRM #5 received
   Got 5 signals, stopping.
   Done.
*/

๐Ÿ’ป Example 3: Inspect Timer State with getitimer()

Query how much time is left before the timer fires.

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

void handler(int sig) { printf("Timer fired!\n"); }

int main(void) {
    struct itimerval set_val, cur_val;
    struct sigaction sa;

    sa.sa_handler = handler;
    sa.sa_flags   = 0;
    sigemptyset(&sa.sa_mask);
    sigaction(SIGALRM, &sa, NULL);

    /* Set timer: fire after 5 seconds, no repeat */
    set_val.it_value.tv_sec    = 5;
    set_val.it_value.tv_usec   = 0;
    set_val.it_interval.tv_sec  = 0;
    set_val.it_interval.tv_usec = 0;

    setitimer(ITIMER_REAL, &set_val, NULL);
    printf("Timer set for 5 seconds.\n");

    /* Sleep 2 seconds, then inspect */
    sleep(2);
    getitimer(ITIMER_REAL, &cur_val);
    printf("Time remaining: %ld.%06ld seconds\n",
           cur_val.it_value.tv_sec,
           cur_val.it_value.tv_usec);
    /* Expected: ~3 seconds remaining */

    pause(); /* wait for the signal */
    return 0;
}

/* Output:
   Timer set for 5 seconds.
   Time remaining: 2.999821 seconds
   Timer fired!
*/

๐Ÿ“Œ Key Points to Remember
โš ๏ธ One Timer Per Type
Each process can have only ONE timer of each type. A second setitimer() replaces the first.
โœ… alarm() = simplified setitimer()
alarm() uses the same ITIMER_REAL timer. Never mix them in the same program.
๐Ÿ” fork() vs exec()
Timers are NOT inherited by child via fork(), but ARE preserved across exec().
๐ŸŽฏ Default action = kill
Default disposition of SIGALRM, SIGVTALRM, SIGPROF is process termination โ€” always install a handler!

๐ŸŽ“ Interview Questions
Q1. What are the three types of interval timers in Linux? Which signal does each generate?

ITIMER_REAL โ†’ SIGALRM (wall time), ITIMER_VIRTUAL โ†’ SIGVTALRM (user CPU time), ITIMER_PROF โ†’ SIGPROF (user+kernel CPU time).

Q2. What happens if you call setitimer() when a timer is already set?

It replaces the existing timer. The old settings can be retrieved via the old_value argument.

Q3. How do you cancel an active timer?

Call setitimer() with both it_value fields set to 0. Or call alarm(0) for ITIMER_REAL.

Q4. Are interval timers inherited by child processes after fork()?

No. Timers are NOT inherited via fork(). They ARE preserved across exec().

Q5. What is the difference between alarm() and setitimer()?

alarm() is a simpler API โ€” one-shot only, seconds precision, returns remaining time. setitimer() supports microsecond precision, repeating intervals, and all three timer types. Both share the same ITIMER_REAL timer on Linux.

Q6. What is the purpose of the it_interval field in itimerval?

After each expiry, the timer is reloaded with it_interval. If both fields are 0, the timer is one-shot. If non-zero, it repeats at that interval โ€” a periodic timer.

Next: Timer Scheduling & Accuracy โ†’

Learn how the kernel jiffy affects timer precision and high-resolution timers.

Part 2: Scheduling & Accuracy Back to Index

Leave a Reply

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