About This Chapter
Chapter 36 of TLPI covers everything a Linux systems programmer needs to know about process resource management. Every running process consumes resources — CPU time, virtual memory, file descriptors, signal queues. Linux gives you full programmatic control over monitoring (getrusage()) and limiting (getrlimit() / setrlimit()) these resources.
This chapter is split into 28 separate HTML files — one for every section and subsection. Each file covers theory, a code example in a pre/code block, and interview questions.
Key Terms
Section 36.1 — Process Resource Usage (getrusage)
Introduction to the getrusage() system call. Covers the function signature, the three who flags (RUSAGE_SELF, RUSAGE_CHILDREN, RUSAGE_THREAD), what the call returns, and when to use each flag.
Deep dive into all 17 fields of struct rusage. Explains which 9 are actually used on Linux, which 8 are BSD legacy zeros, and what each used field means — CPU time, page faults, context switches, RSS.
How child resource usage is accumulated through the process tree. The wait() dependency rule, grandchild scenario, ru_maxrss is a max not a sum for children, and the pre-2.6.9 SIGCHLD deviation bug.
Section 36.2 — Process Resource Limits
What resource limits are, why they matter, the ulimit/limit shell commands, and how /proc/PID/limits (since 2.6.24) lets you view any process’s limits without writing code.
Function signatures, the struct rlimit with rlim_cur and rlim_max, the rlim_t data type, RLIM_INFINITY, and safe printing with (long long) cast and %lld format specifier.
Who can change what: privileged vs unprivileged processes, irreversibility of hard limit lowering, CAP_SYS_RESOURCE, fork/exec inheritance, per-user-ID scoped limits, and the complete Table 36-1 of all 15 constants.
Full walkthrough of Listing 36-2 (printRlimit helper) and Listing 36-3 (RLIMIT_NPROC demo). Explains why only 4 children were created (26 pre-existing), EAGAIN error handling, and zombie accumulation.
The 32-bit vs 64-bit rlim_t mismatch on x86-32. RLIM_SAVED_CUR and RLIM_SAVED_MAX constants, what happens when _FILE_OFFSET_BITS=64 expands rlim_t to 64 bits, and glibc’s silent RLIM_INFINITY conversion behaviour.
Section 36.3 — Details of Specific Resource Limits
The Section 36.3 introduction: how limits get set in practice (ulimit, /proc, setrlimit), complete Table 36-1 with all 15 constants, categorisation by type (memory/CPU/file/IPC), and the three patterns of breach behaviour (signal+error, error only, signal only).
Virtual address space size limit. brk/sbrk/mmap/mremap/shmat fail with ENOMEM on breach. How malloc() hits this limit. Interaction with stack growth.
Core dump file size limit. Setting to 0 disables core dumps entirely. Security use case (prevent memory contents being dumped to disk). RLIMIT_FSIZE interaction (whichever is smaller wins).
CPU time limit in seconds. SIGXCPU at soft limit (once per second thereafter), SIGKILL at hard limit. Portable signal handler pattern. How UNIX implementations differ in post-SIGXCPU behaviour.
Data segment size limit — the sum of .data + .bss + heap. sbrk()/brk() fail with ENOMEM when the heap tries to grow past this limit. malloc() returns NULL as a result.
Maximum file size limit. SIGXFSZ signal AND EFBIG error are both generated simultaneously when write() or truncate() would exceed the soft limit. Default action is core dump.
Locked (non-swappable) memory limit. Affects mlock(), mlockall(), and locking options of mmap() and shmctl(). MCL_FUTURE flag can cause later brk/mmap/mremap to fail if the limit is set too low.
POSIX message queue byte limit per real user ID. The byte formula: maxmsg × sizeof(msg_msg*) + maxmsg × msgsize. The sizeof(msg_msg*) addend prevents zero-length message flooding. Linux-specific since 2.6.8.
Nice value ceiling for unprivileged processes. The formula: max nice = 20 − rlim_cur. Affects setpriority() and nice(). Linux-specific since 2.6.12. Why the inverted formula is used.
Maximum file descriptor number + 1. EMFILE on open/socket/pipe/dup. NR_OPEN hard ceiling (pre-2.6.25) vs /proc/sys/fs/nr_open (2.6.25+). System-wide file-max limit. sysconf(_SC_OPEN_MAX) behaviour.
Maximum processes/threads per real user ID. fork/vfork/clone fail with EAGAIN. threads-max system file. sysconf(_SC_CHILD_MAX) bug fixed in 2.6.23. Scanning /proc/PID/status Uid to estimate current count.
Resident set size limit — present but not enforced on modern Linux. Historical context: it had a minor effect on MADV_WILLNEED in old 2.4 kernels (up to 2.4.29). Why Linux never fully implemented it.
Realtime scheduling priority ceiling. Affects sched_setscheduler() and sched_setparam(). Linux-specific since 2.6.12. Important for embedded real-time Linux systems (PREEMPT_RT patch).
Realtime CPU time limit in microseconds — prevents a runaway RT process from locking the system. SIGXCPU at soft limit, SIGKILL at hard limit, same as RLIMIT_CPU. Linux-specific since 2.6.25.
Maximum queued signals per real user ID. sigqueue() fails with EAGAIN on breach. kill() still works even at the limit (one instance of each non-queued signal). SigQ in /proc/PID/status. Linux-specific since 2.6.8.
Maximum stack size. SIGSEGV on overflow — requires alternate signal stack to catch. Since 2.6.23, this limit also controls space for command-line arguments and environment variables passed to execve().
Sections 36.4 and 36.5 — Summary and Exercises
Consolidated summary of the entire chapter. getrusage() and its three who flags, the soft/hard limit model, privilege rules, fork/exec inheritance, and a quick review of all 15 resource limit constants.
All three chapter exercises with complete solution code. Exercise 36-1: RUSAGE_CHILDREN wait() dependency. Exercise 36-2: rusage command wrapper (like /usr/bin/time). Exercise 36-3: behaviour when consumption already exceeds the new soft limit.
Complete File List (28 Files)
Ready to Learn?
Start from the beginning or jump to any section above.
