RLIMIT_NPROC Process Count per Real User ID: fork/EAGAIN, threads-max, /proc/PID/status

 

36.3 — RLIMIT_NPROC
Process Count per Real User ID: fork/EAGAIN, threads-max, /proc/PID/status | EmbeddedPathashala

What is RLIMIT_NPROC?

RLIMIT_NPROC limits the maximum number of processes (and threads) that can exist for the real user ID of the calling process. It is BSD-derived, not in SUSv3, and available on Linux and the BSDs.

Note: despite the name “NPROC”, this limit actually counts threads, not just processes. Threads are created with clone() and each counts against RLIMIT_NPROC just like a process created with fork().

Which Calls Are Affected

When the real-user-ID process count is at or above the soft RLIMIT_NPROC limit, these calls fail with EAGAIN:

fork()
vfork()
clone()

This limit is not enforced for processes with CAP_SYS_ADMIN or CAP_SYS_RESOURCE capabilities.

Per-User-ID Scope

RLIMIT_NPROC counts all processes with the same real user ID, system-wide — not just the children of the current process. This is why in the textbook example, setting the limit to 30 but having 26 pre-existing processes meant only 4 more could be created.

The limit is only checked in processes that have set it or inherited it. Another process owned by the same user that has RLIMIT_NPROC set to RLIM_INFINITY is not constrained.

System-Wide Thread Limit: /proc/sys/kernel/threads-max

Independently of RLIMIT_NPROC, Linux imposes a system-wide cap on the total number of threads (processes) across all users. This limit is in /proc/sys/kernel/threads-max (Linux 2.4+). Even root cannot exceed this. The default value is computed at boot based on available physical memory.

# View system-wide thread limit
$ cat /proc/sys/kernel/threads-max
62689

# Raise it (requires root)
# echo 100000 > /proc/sys/kernel/threads-max

Finding Current Process Count for a User ID

There is no direct system call to query “how many processes does user X currently have?” The portable workaround on Linux is to scan /proc/PID/status files and look at the Uid field:

# The Uid line in /proc/PID/status format:
# Uid: real  effective  saved-set  filesystem
$ grep "^Uid:" /proc/*/status 2>/dev/null | awk '{print $2}' | sort | uniq -c
    # Shows count of processes per real UID

# Or: count processes for the current user
$ ps -u $(id -u) --no-headers | wc -l
Caveat: By the time a /proc scan completes, the data may already be stale — processes can be created or destroyed during the scan.

Code Example — RLIMIT_NPROC with fork() Loop

#include 
#include 
#include 
#include 
#include <sys/resource.h>
#include <sys/wait.h>

int main(void)
{
    struct rlimit rl;
    pid_t pid;
    int children = 0;

    /* Set RLIMIT_NPROC: soft=5 extra processes, hard=10 */
    getrlimit(RLIMIT_NPROC, &rl);
    printf("Current NPROC: soft=%lld hard=%lld\n",
           (long long)rl.rlim_cur, (long long)rl.rlim_max);

    /* Lower soft to current_count + 3 so we can create only ~3 more */
    rl.rlim_cur = 10;   /* allow 10 total for this user */
    rl.rlim_max = 20;
    setrlimit(RLIMIT_NPROC, &rl);

    /* Fork in a loop until EAGAIN */
    while (1) {
        pid = fork();
        if (pid == -1) {
            if (errno == EAGAIN) {
                printf("fork() EAGAIN: RLIMIT_NPROC hit after %d children\n",
                       children);
                break;
            }
            perror("fork"); break;
        }
        if (pid == 0) {
            sleep(5);   /* Child: stay alive briefly */
            _exit(0);
        }
        children++;
        printf("  Created child %d (PID %d)\n", children, pid);
    }

    /* Clean up */
    while (wait(NULL) != -1) ;
    return 0;
}
/* Compile: gcc -o nproc_demo nproc_demo.c
   Note: actual number of children depends on pre-existing processes */

Interview Questions

Q1. RLIMIT_NPROC is described as a “process” limit but actually counts threads too — why?

On Linux, threads are created with clone() just like processes. The kernel sees them as lightweight processes sharing resources. RLIMIT_NPROC is enforced by clone(), so every thread creation also counts against this limit. The name predates the widespread use of POSIX threads but the implementation counts both.

Q2. What error does fork() return when RLIMIT_NPROC is exceeded?

EAGAIN (Resource temporarily unavailable). The same errno value is returned by vfork() and clone(). It is “temporary” because the limit could be freed if other processes with the same user ID exit.

Q3. What is the SUSv3-compliant way to query the maximum allowed processes for a user ID?

sysconf(_SC_CHILD_MAX). On Linux, before 2.6.23, this always returned 999 (inaccurate). Since 2.6.23 with glibc 2.4+, it correctly returns the RLIMIT_NPROC soft limit value.

Q4. Is RLIMIT_NPROC enforced for root?

No. RLIMIT_NPROC is not enforced for processes with CAP_SYS_ADMIN or CAP_SYS_RESOURCE capabilities. However, the system-wide threads-max limit in /proc/sys/kernel/threads-max applies to everyone including root.

Leave a Reply

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