What Does This Chapter Cover?
When a program runs on Linux it does not exist in a vacuum. It competes with other processes for CPU time, physical memory, and file descriptors. The operating system needs a way to track what each process has used and, when necessary, stop a process from consuming more than its fair share. Chapter 36 of The Linux Programming Interface gives you the tools to do exactly this from inside your own programs.
The chapter is divided into two major topics that work together:
Topic 1 — Resource Monitoring
The getrusage() system call lets a process ask the kernel: “How much CPU time have I used? How many page faults occurred? How many context switches happened?” This is the measurement side — you are reading usage statistics that the kernel has been accumulating for your process.
Think of it like the fuel gauge and trip computer in a car — you are reading the instrument panel to see what you have already consumed.
Topic 2 — Resource Limiting
The getrlimit() and setrlimit() system calls let a process retrieve and set hard caps on how much of a resource it (and its descendants) may use. Once a limit is set, the kernel enforces it — usually by sending a signal or returning an error.
Think of it like the speed governor on a commercial truck — a hard ceiling that prevents the vehicle from ever going above a certain speed, regardless of what the driver does.
int setrlimit(int resource, const struct rlimit *rlim);
Why Does This Matter for Embedded / Systems Engineers?
In desktop applications a process consuming too much memory might just cause the program to crash. In an embedded system or a production server, one runaway process can starve every other process of resources and bring the whole system down.
A BLE stack daemon that leaks file descriptors will eventually hit RLIMIT_NOFILE and fail to accept new connections. Setting and monitoring this limit is essential.
Before exec’ing a user-supplied binary, a parent process should use setrlimit() to cap CPU time, memory, and file descriptors so the child cannot harm the system.
getrusage() tells you exactly how much CPU time and how many page faults your code caused — essential data for optimising embedded firmware running on Linux.
The shell’s built-in
ulimit command uses setrlimit() internally. Understanding the underlying API lets you script and automate resource limits precisely.System Calls at a Glance
Code Example — All Three Calls Together
This small program shows all three system calls working together. It reads the current CPU limit, sets a tighter one, then checks the process’s own CPU usage:
#include <stdio.h>
#include <stdlib.h>
#include <sys/resource.h>
int main(void)
{
struct rlimit lim;
struct rusage usage;
/* ---- Step 1: Read the current CPU time limit ---- */
if (getrlimit(RLIMIT_CPU, &lim) == -1) {
perror("getrlimit"); exit(1);
}
if (lim.rlim_cur == RLIM_INFINITY)
printf("Current CPU soft limit : unlimited\n");
else
printf("Current CPU soft limit : %lld seconds\n",
(long long)lim.rlim_cur);
/* ---- Step 2: Set a new soft CPU limit of 60 seconds ---- */
lim.rlim_cur = 60; /* soft: 60 seconds */
/* leave lim.rlim_max unchanged (keep the existing hard limit) */
if (setrlimit(RLIMIT_CPU, &lim) == -1) {
perror("setrlimit"); exit(1);
}
printf("New CPU soft limit set to 60 seconds\n");
/* ---- Step 3: Read this process's current resource usage ---- */
if (getrusage(RUSAGE_SELF, &usage) == -1) {
perror("getrusage"); exit(1);
}
printf("User CPU used so far : %ld.%06ld s\n",
(long)usage.ru_utime.tv_sec,
(long)usage.ru_utime.tv_usec);
printf("Sys CPU used so far : %ld.%06ld s\n",
(long)usage.ru_stime.tv_sec,
(long)usage.ru_stime.tv_usec);
return 0;
}
/* Compile: gcc -o ch36_intro ch36_intro.c
Run: ./ch36_intro */
Interview Questions — Chapter Introduction
getrusage() — reads resource usage statistics (CPU time, page faults, context switches) for the calling process or its children. getrlimit() — reads the current soft and hard limits for a specified resource. setrlimit() — changes the soft and/or hard limits for a specified resource. All three require #include <sys/resource.h>.
Monitoring (getrusage) is passive — you are reading statistics that the kernel has already accumulated. Limiting (setrlimit) is active — you are instructing the kernel to enforce a cap on future consumption. Once a limit is set and the process reaches it, the kernel takes action: it either sends a signal or causes a system call to fail with an error.
Embedded and real-time Linux systems often run multiple critical daemons on hardware with limited RAM and CPU. A single buggy process that consumes all memory or all file descriptors can starve other critical daemons and crash the system. Resource limits are the mechanism to enforce isolation and prevent such cascading failures. They are also used before exec()-ing untrusted or third-party code.
Bash uses the built-in ulimit command, which calls setrlimit() internally. When bash forks a child to run a command, the child inherits the limits that were set in bash. The child cannot raise the limits above what the shell set (unless it is privileged). This inheritance chain is how system administrators deploy resource budgets for user processes.
