setitimer()
SIGALRM
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:
| 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 |
setitimer()
called
Timer counts
down from
it_value โ 0
Signal sent
(e.g. SIGALRM)
If it_interval
โ 0, reload
& repeat
alarm(0)
to stop
struct itimerval {
struct timeval it_interval;
/* Repeat interval */
struct timeval it_value;
/* Time until expiry */
};
struct timeval {
time_t tv_sec;
/* Seconds */
suseconds_t tv_usec;
/* Microseconds */
};
it_interval is all zeros โ one-shot timer. If non-zero โ repeating timer reloaded after each expiry.#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 */
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.
*/
gcc alarm_demo.c -o alarm_demo && ./alarm_demoA 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.
*/
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!
*/
Each process can have only ONE timer of each type. A second
setitimer() replaces the first.alarm() uses the same ITIMER_REAL timer. Never mix them in the same program.Timers are NOT inherited by child via
fork(), but ARE preserved across exec().Default disposition of SIGALRM, SIGVTALRM, SIGPROF is process termination โ always install a handler!
ITIMER_REAL โ SIGALRM (wall time), ITIMER_VIRTUAL โ SIGVTALRM (user CPU time), ITIMER_PROF โ SIGPROF (user+kernel CPU time).
It replaces the existing timer. The old settings can be retrieved via the old_value argument.
Call setitimer() with both it_value fields set to 0. Or call alarm(0) for ITIMER_REAL.
No. Timers are NOT inherited via fork(). They ARE preserved across exec().
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.
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.
Learn how the kernel jiffy affects timer precision and high-resolution timers.
