POSIX Shared Memory

POSIX Shared Memory
Chapter 54 โ€” Part 1 of 5 | The Linux Programming Interface
5
Parts in Series
IPC
Topic Area
POSIX
Standard

๐Ÿ“š Chapter 54 Series
Part 1: Introduction & Overview Part 2: shm_open() Part 3: ftruncate() & fstat() Part 4: mmap() with POSIX shm Part 5: shm_unlink() & Examples

๐Ÿ”‘ Key Concepts in This Part
POSIX Shared Memory IPC System V vs POSIX tmpfs /dev/shm Kernel Persistence shm_open() mmap() File Descriptor

What Is POSIX Shared Memory?

When two or more processes need to exchange large amounts of data quickly, shared memory is the fastest IPC mechanism available. Unlike pipes or message queues, shared memory avoids any kernel copying of data โ€” processes read and write directly to a common region of memory.

POSIX shared memory was introduced by the POSIX.1b realtime standard as a cleaner alternative to the older System V shared memory API. The goal was to provide shared memory that fits naturally into the familiar UNIX model of filenames and file descriptors.

โš ๏ธ Why Not System V Shared Memory?

System V shared memory (covered in Chapter 48) works, but it has two well-known friction points:

โŒ System V Model
Uses keys and identifiers
Needs new system calls (shmget, shmat, shmctl)
Not consistent with UNIX I/O model
Separate commands to manage
โœ… POSIX Model
Uses names and file descriptors
Reuses existing calls (ftruncate, fstat, mmap)
Consistent with standard UNIX I/O model
Normal filesystem tools work on it

โš ๏ธ Why Not Shared File Mappings?

Section 49.4.2 of TLPI showed that two processes can share memory by mapping the same file with MAP_SHARED. This works, but it has one annoying requirement: you must create an actual disk file even if you never want persistent storage. Creating a disk file means:

  • Extra step of creating and naming a backing file
  • File I/O overhead (disk reads/writes during setup)
  • Cleanup burden โ€” you must delete the file when done

POSIX shared memory eliminates the disk file entirely. It lives in a RAM-based filesystem called tmpfs.

How POSIX Shared Memory Works โ€” Big Picture

Using POSIX shared memory always follows the same two-step pattern:

1
shm_open()
Open or create the shared memory object. Get back a file descriptor.
โ†’
2
mmap()
Map the file descriptor into the process’s virtual address space using MAP_SHARED.

This two-step design is intentional and historical. When POSIX added shared memory, mmap() already existed. The committee simply decided: instead of calling open() on a disk file, call shm_open() to get a file descriptor for a RAM-resident object, then pass that descriptor to mmap() as usual.

๐Ÿ”„ Analogy: System V vs POSIX

The table below maps corresponding calls between the two APIs:

Operation System V POSIX
Create / Open shmget() shm_open()
Attach / Map shmat() mmap()
Detach / Unmap shmdt() munmap()
Control / Remove shmctl() shm_unlink()
Identifier type Integer ID (shmid) File descriptor (fd)

๐Ÿ—‚๏ธ Where Does POSIX Shared Memory Live? (Linux)

The POSIX standard does not specify how shared memory objects should be stored internally. Linux uses a dedicated tmpfs filesystem mounted at /dev/shm.

# Linux POSIX shared memory location
$ ls -l /dev/shm
total 0
-rw——- 1 ravi users 10000 Jun 12 11:31 demo_shm
# Check tmpfs mount
$ df -h /dev/shm
Filesystem Size Used Avail Use% Mounted on
tmpfs 256M 0 256M 0% /dev/shm
โšก Kernel Persistence

Objects in /dev/shm survive even if no process currently has them open. But they are lost on system reboot because tmpfs is RAM-based.

๐Ÿ“ Size Limit

Total POSIX shm is limited by the tmpfs size (default often 256 MB). The superuser can resize it: mount -o remount,size=512m /dev/shm

๐Ÿ’ป Quick Example: Creating a POSIX Shared Memory Object

Below is a minimal complete example showing the two-step process. We create a 4096-byte shared memory object, map it, write a string, then read it back.

/*
 * posix_shm_intro.c
 * Demonstrates the two-step POSIX shm pattern:
 *   Step 1: shm_open()  - get a file descriptor
 *   Step 2: mmap()      - map into address space
 *
 * Compile: gcc posix_shm_intro.c -o posix_shm_intro -lrt
 * Run:     ./posix_shm_intro
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>          /* O_CREAT, O_RDWR */
#include <sys/mman.h>       /* shm_open, mmap  */
#include <sys/stat.h>       /* mode constants  */
#include <unistd.h>         /* ftruncate       */

#define SHM_NAME   "/ep_demo"
#define SHM_SIZE   4096

int main(void)
{
    int fd;
    void *addr;

    /* ---- STEP 1: shm_open() ---- */
    /* Create (O_CREAT) and open for read-write (O_RDWR).
     * O_EXCL would fail if it already exists โ€” omitted here for simplicity.
     * 0600 = owner read+write permissions.
     */
    fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0600);
    if (fd == -1) {
        perror("shm_open");
        exit(EXIT_FAILURE);
    }
    printf("shm_open() succeeded. fd = %d\n", fd);

    /* A new object starts at zero length.
     * We must call ftruncate() to set the desired size BEFORE mmap().
     */
    if (ftruncate(fd, SHM_SIZE) == -1) {
        perror("ftruncate");
        exit(EXIT_FAILURE);
    }
    printf("ftruncate() set size to %d bytes\n", SHM_SIZE);

    /* ---- STEP 2: mmap() ---- */
    /* MAP_SHARED means writes are visible to other processes
     * that map the same object.
     */
    addr = mmap(NULL, SHM_SIZE, PROT_READ | PROT_WRITE,
                MAP_SHARED, fd, 0);
    if (addr == MAP_FAILED) {
        perror("mmap");
        exit(EXIT_FAILURE);
    }
    printf("mmap() succeeded. Mapped at %p\n", addr);

    /* The file descriptor can be closed after mmap().
     * The mapping stays valid.
     */
    close(fd);

    /* Write to shared memory like normal memory */
    snprintf((char *)addr, SHM_SIZE, "Hello from EmbeddedPathashala!");
    printf("Wrote: %s\n", (char *)addr);

    /* Read it back */
    printf("Read back: %s\n", (char *)addr);

    /* Cleanup */
    munmap(addr, SHM_SIZE);
    shm_unlink(SHM_NAME);   /* Remove the shared memory object */

    printf("Done. Shared memory removed.\n");
    return 0;
}
Expected Output:

shm_open() succeeded. fd = 3
ftruncate() set size to 4096 bytes
mmap() succeeded. Mapped at 0x7f3a2b000000
Wrote: Hello from EmbeddedPathashala!
Read back: Hello from EmbeddedPathashala!
Done. Shared memory removed.
โš ๏ธ Link with -lrt
On older Linux systems you must link with -lrt (realtime library) for shm_open() and shm_unlink(). On modern glibc they are in libc but the flag does not hurt.

๐ŸŽฏ Interview Questions โ€” Introduction
Q1. What are the two main drawbacks of System V shared memory?
Answer: (1) It uses keys and integer identifiers, which are inconsistent with the standard UNIX model of filenames and file descriptors, requiring entirely new system calls. (2) It does not integrate with mmap() or other standard file-descriptor-based calls, so you need shmget/shmat/shmctl โ€” a completely separate API.
Q2. Why is using a shared file mapping (MAP_SHARED on a disk file) not ideal for IPC?
Answer: You must create an actual disk file even when you have no need for persistent storage. This adds the inconvenience of file creation/deletion and incurs unnecessary file I/O overhead during setup.
Q3. What filesystem does Linux use for POSIX shared memory, and where is it mounted?
Answer: Linux uses tmpfs, a RAM-based virtual filesystem. It is mounted at /dev/shm. Shared memory objects appear as files under that directory.
Q4. What does “kernel persistence” mean in the context of POSIX shared memory?
Answer: A POSIX shared memory object persists until it is explicitly deleted with shm_unlink() or the system is rebooted. Even if all processes that have it open exit, the object remains accessible in /dev/shm โ€” unlike a pipe, which disappears when all file descriptors to it are closed.
Q5. What is the two-step process for using POSIX shared memory?
Answer: Step 1 โ€” call shm_open() to create or open the shared memory object; this returns a file descriptor. Step 2 โ€” pass that file descriptor to mmap() with MAP_SHARED to map the object into the process’s virtual address space.
Q6. What is the analogy between System V and POSIX shared memory APIs?
Answer: shm_open() is analogous to shmget() (create/obtain), and mmap() is analogous to shmat() (attach/map). Similarly, munmap() โ†” shmdt(), and shm_unlink() โ†” shmctl(IPC_RMID,...).
Q7. Can you close the file descriptor returned by shm_open() after calling mmap()?
Answer: Yes. Once mmap() has been called, the mapping remains valid even if you close the file descriptor. However, you may want to keep it open if you need to call fstat() or ftruncate() later to inspect or resize the object.

Continue the Series
Next: shm_open() in detail โ€” flags, permissions, naming rules

โ† Part 1: Introduction Part 2: shm_open() โ†’

Leave a Reply

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