RLIMIT_MEMLOCK Locked Memory Limit: mlock(), mlockall(), MCL_FUTURE

 

36.3 — RLIMIT_MEMLOCK
Locked Memory Limit: mlock(), mlockall(), MCL_FUTURE | EmbeddedPathashala

What is RLIMIT_MEMLOCK?

RLIMIT_MEMLOCK limits the number of bytes of virtual memory a process may lock into physical memory (RAM), preventing those pages from being swapped out to disk. This is a BSD-derived limit — not in SUSv3 — but available on Linux and the BSDs.

Locking memory is important in real-time and embedded contexts: swapping a page out and back introduces unpredictable latency spikes. By locking critical pages (like your BLE protocol handler or audio buffer), you guarantee they are always in RAM.

Which System Calls Are Affected

RLIMIT_MEMLOCK governs how much memory can be locked. The affected calls are:

mlock(addr, len)
Locks a specific address range. Fails with ENOMEM if the amount to lock exceeds RLIMIT_MEMLOCK.
mlockall(flags)
Locks all current and/or future pages. Uses MCL_CURRENT and/or MCL_FUTURE flags.
mmap(MAP_LOCKED)
The MAP_LOCKED flag in mmap() also counts against RLIMIT_MEMLOCK.
shmctl(SHM_LOCK)
Locking System V shared memory segments also counts against this limit.

The MCL_FUTURE Complication

When mlockall(MCL_FUTURE) is called, it tells the kernel: “lock every page I map in the future too, not just the pages I have now.” This creates a latent constraint: any subsequent call to brk(), sbrk(), mmap(), or mremap() that would push the locked-memory total past RLIMIT_MEMLOCK will fail.

/* MCL_FUTURE: lock all future pages too */
mlockall(MCL_FUTURE);

/* Any of these may later fail with ENOMEM if
   the new pages would exceed RLIMIT_MEMLOCK: */
malloc(large_amount);    /* internally calls sbrk()/mmap() */
mmap(NULL, size, ...);   /* anonymous mapping */
mremap(old, old_sz, new_sz, ...); /* expand mapping */
Real-time programming note: Real-time applications typically call mlockall(MCL_CURRENT | MCL_FUTURE) at startup to guarantee all code and data is always in RAM. This requires either root privileges or a sufficiently high RLIMIT_MEMLOCK.

Code Example — mlock() and RLIMIT_MEMLOCK

#define _GNU_SOURCE
#include 
#include 
#include 
#include 
#include <sys/mman.h>
#include <sys/resource.h>

int main(void)
{
    struct rlimit rl;

    /* Check current memlock limit */
    getrlimit(RLIMIT_MEMLOCK, &rl);
    printf("RLIMIT_MEMLOCK: soft=%lld hard=%lld bytes\n",
           (long long)rl.rlim_cur, (long long)rl.rlim_max);

    /* Allocate 1 MB and try to lock it */
    size_t sz = 1024 * 1024;
    void *buf = mmap(NULL, sz, PROT_READ|PROT_WRITE,
                     MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
    if (buf == MAP_FAILED) { perror("mmap"); exit(1); }

    /* Touch all pages so they are faulted in */
    memset(buf, 0, sz);

    /* Lock: will fail with ENOMEM if sz > RLIMIT_MEMLOCK soft */
    if (mlock(buf, sz) == -1) {
        if (errno == ENOMEM)
            printf("mlock failed: ENOMEM (RLIMIT_MEMLOCK exceeded)\n");
        else if (errno == EPERM)
            printf("mlock failed: EPERM (need root or higher limit)\n");
        else
            perror("mlock");
    } else {
        printf("Locked 1 MB in RAM successfully\n");
        munlock(buf, sz);
    }

    munmap(buf, sz);
    return 0;
}
/* Compile: gcc -o memlock_demo memlock_demo.c
   Note: unprivileged processes on many systems have
   RLIMIT_MEMLOCK = 64 KB, so locking 1 MB will fail
   unless you are root or the limit is raised. */

Interview Questions

Q1. Why would a real-time application call mlockall()?

Real-time applications lock all their memory to prevent page faults. A page fault causes the kernel to read a page from disk (major fault) or remap a cached page (minor fault). Either case introduces unpredictable latency that can violate real-time deadlines. By calling mlockall(MCL_CURRENT | MCL_FUTURE) at startup, all code and data pages are guaranteed to be in RAM — eliminating fault-induced jitter.

Q2. What error does mlock() return when RLIMIT_MEMLOCK is exceeded?

ENOMEM. The mlock() call fails and errno is set to ENOMEM. Note that EPERM is returned if the process lacks the CAP_IPC_LOCK capability and RLIMIT_MEMLOCK is 0.

Q3. What flag in mlockall() causes future mappings to also be locked?

MCL_FUTURE. When mlockall(MCL_FUTURE) is called, every subsequent memory mapping (brk(), mmap(), mremap()) will be automatically locked into RAM. If any such call would push the locked total past RLIMIT_MEMLOCK, it fails with ENOMEM.

Q4. Is RLIMIT_MEMLOCK available on all UNIX systems?

No. It is BSD-derived and absent from SUSv3. It is available on Linux and the BSDs but not on all UNIX systems. Code using RLIMIT_MEMLOCK is therefore not portable to all POSIX-compliant systems.

Leave a Reply

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