RLIMIT_CPU CPU Time Limit: SIGXCPU, SIGKILL & Signal Handling

 

36.3 — RLIMIT_CPU
CPU Time Limit: SIGXCPU, SIGKILL & Signal Handling | EmbeddedPathashala

What is RLIMIT_CPU?

RLIMIT_CPU limits the total amount of CPU time (in seconds, combining both user-mode and kernel-mode execution) that a process may consume. This is a powerful resource limit for preventing runaway computation — infinite loops, recursive explosions, or heavy scientific calculations that should not run forever.

This limit is specified by SUSv3 and is widely available across all UNIX systems.

How Enforcement Works — Two Stages

RLIMIT_CPU enforcement is signal-based and has two distinct stages corresponding to the soft and hard limits:

Stage 1 — Soft Limit Reached: SIGXCPU sent
When the process has consumed CPU time equal to the soft RLIMIT_CPU limit, the kernel sends it a SIGXCPU signal. The default action for SIGXCPU is to terminate the process with a core dump. On Linux, if the process catches SIGXCPU and returns, the kernel sends another SIGXCPU for each additional second of CPU time consumed.
Stage 2 — Hard Limit Reached: SIGKILL sent
If the process continues consuming CPU time past the hard RLIMIT_CPU limit, the kernel sends a SIGKILL signal, which cannot be caught or ignored. The process is unconditionally terminated.
Portable coding recommendation: UNIX implementations vary in how they handle SIGXCPU after the first delivery. For portable code, design your SIGXCPU handler to do cleanup and exit on first receipt, rather than relying on repeated signals.

SIGXCPU Signal Handling Options

When a process receives SIGXCPU, it has three options:

  1. Default action (terminate + core dump) — the process dies when the soft limit is hit. Suitable for most cases.
  2. Catch SIGXCPU and do cleanup — install a handler that saves state, closes files, and exits gracefully. On Linux, the handler will be called again each second until the hard limit is hit and SIGKILL terminates it.
  3. Catch SIGXCPU and raise the limit — inside the handler, call setrlimit() to increase RLIMIT_CPU and continue. Only works if the process has sufficient privilege to raise the limit, or if the new limit is within the hard limit.

Code Example — RLIMIT_CPU with SIGXCPU Handler

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/resource.h>

static void sigxcpu_handler(int sig)
{
    /* Called each second after soft CPU limit is hit */
    printf("\nSIGXCPU received! Doing cleanup and exiting.\n");
    exit(1);  /* Exit before hard limit causes SIGKILL */
}

int main(void)
{
    struct rlimit rl;

    /* Install handler for SIGXCPU */
    signal(SIGXCPU, sigxcpu_handler);

    /* Set soft CPU limit to 2 seconds, hard to 5 seconds */
    rl.rlim_cur = 2;   /* soft: send SIGXCPU after 2 sec */
    rl.rlim_max = 5;   /* hard: SIGKILL after 5 sec      */
    if (setrlimit(RLIMIT_CPU, &rl) == -1) {
        perror("setrlimit"); exit(1);
    }

    printf("CPU limit: soft=2s hard=5s. Running infinite loop...\n");

    /* Infinite loop — will eventually hit the CPU limit */
    volatile long i = 0;
    while (1) {
        i++;  /* Burns CPU in user mode */
    }

    return 0;  /* Never reached */
}

/* Compile: gcc -O0 -o rlimit_cpu rlimit_cpu.c
   Run:     ./rlimit_cpu
   Expected: after ~2 seconds of CPU time, SIGXCPU handler fires. */

Interview Questions

Q1. What signal is sent when a process reaches the soft RLIMIT_CPU limit?

SIGXCPU is sent. The default action is to terminate the process with a core dump. If the process catches SIGXCPU and returns, Linux sends another SIGXCPU for each additional second of CPU time consumed, until the hard limit is hit.

Q2. What signal is sent when a process reaches the hard RLIMIT_CPU limit?

SIGKILL is sent. This signal cannot be caught, blocked, or ignored. The process is unconditionally terminated by the kernel. This is the final enforcement backstop after SIGXCPU signals have been delivered.

Q3. Does RLIMIT_CPU measure wall-clock time or CPU time?

CPU time (total time the process was actually running on a CPU, both user-mode and kernel-mode). Wall-clock time is different — a process sleeping for 10 minutes consumes near-zero CPU time even though 10 minutes pass. RLIMIT_CPU only counts time the process was actually executing.

Q4. What is the portable way to handle SIGXCPU?

For portable code, the SIGXCPU handler should do required cleanup and exit on first receipt. UNIX systems vary in how they deliver subsequent SIGXCPU signals. On Linux they come once per second until the hard limit; on some other systems only one SIGXCPU is sent. Relying on repeated signals is not portable.

Leave a Reply

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