shm_open() Creating and Opening POSIX Shared Memory Objects

 

shm_open()
Creating and Opening POSIX Shared Memory Objects
Step 1
of 4
syscall
shm_open
returns
fd

The Role of shm_open()

shm_open() is the entry point to POSIX shared memory. It either creates a new shared memory object or opens an existing one. The function looks and behaves very much like open() for regular files — on purpose. This design lets you use familiar file descriptor operations on shared memory objects.

The return value is a file descriptor. This fd is used with ftruncate() to set the object’s size, and with mmap() to map it into the process’s address space. After mapping, the fd can be closed without affecting the mapping.

Function Signature
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>

int shm_open(const char *name, int oflag, mode_t mode);
/* Returns: file descriptor on success, -1 on error */

Three parameters:

name
String like "/myobject"

Must start with /
No other / allowed

Portable max length: NAME_MAX - 4

oflag
Bit flags controlling open behavior:

O_RDONLY — read only
O_RDWR — read + write
O_CREAT — create if absent
O_EXCL — fail if exists
O_TRUNC — reset to 0 size

mode
Permission bits (like chmod)

Only used when O_CREAT is set.

Common: 0600
(owner read+write)

Understanding oflag Combinations

The oflag parameter controls what happens depending on whether the object already exists:

Flags Object exists Object absent Use case
O_RDWR Opens it Error (ENOENT) Reader/client opens existing
O_RDWR | O_CREAT Opens it Creates it Writer, don’t care if it exists
O_RDWR | O_CREAT | O_EXCL Error (EEXIST) Creates it Writer, strict — must be new
O_RDONLY Opens read-only Error (ENOENT) Read-only consumer

Naming Rules for Shared Memory Objects

The name must follow specific rules to be portable across POSIX systems:

✓ Valid Names
"/myshm"
"/sensor_data"
"/ipc_buffer_1"
"/app.lock"

Starts with /, no other slashes, reasonable length

✗ Invalid Names
"myshm"        /* no leading / */
"/dir/myshm"   /* embedded / */
"/"            /* just a slash */
""             /* empty */

Missing /, embedded slashes, or empty string

Linux Detail: On Linux, "/myshm" maps to /dev/shm/myshm. You can verify with ls /dev/shm/ after creation.

Code Example 1 — Creator Side (Writer)

The process that creates the shared memory object is the “writer” or “server”. It uses O_CREAT | O_RDWR and must call ftruncate() to give it a non-zero size.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define SHM_NAME  "/ep_demo"
#define SHM_SIZE  4096

int main(void)
{
    int fd;

    /* Step 1: Create the shared memory object */
    fd = shm_open(SHM_NAME,
                  O_CREAT | O_RDWR | O_EXCL,  /* create new, fail if exists */
                  S_IRUSR | S_IWUSR);          /* owner read+write (0600) */

    if (fd == -1) {
        perror("shm_open");
        exit(EXIT_FAILURE);
    }

    printf("Created shared memory object: %s (fd=%d)\n", SHM_NAME, fd);

    /* Step 2: Set the size — object starts at 0 bytes */
    if (ftruncate(fd, SHM_SIZE) == -1) {
        perror("ftruncate");
        shm_unlink(SHM_NAME);   /* clean up before exit */
        exit(EXIT_FAILURE);
    }

    printf("Set size to %d bytes\n", SHM_SIZE);

    /* fd will be used with mmap() next — see next tutorial */
    close(fd);

    return 0;
}

Compile and run:

gcc creator.c -o creator -lrt
./creator
# Created shared memory object: /ep_demo (fd=3)
# Set size to 4096 bytes

ls -la /dev/shm/ep_demo
# -rw------- 1 ravi ravi 4096 Jun 12 10:00 ep_demo

Code Example 2 — Consumer Side (Reader Opens Existing)

The reader process opens the shared memory object that already exists. It does not need to call ftruncate() — the size was already set by the creator.

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define SHM_NAME "/ep_demo"

int main(void)
{
    int fd;
    struct stat sb;

    /* Open existing shared memory object — read-only */
    fd = shm_open(SHM_NAME, O_RDONLY, 0);

    if (fd == -1) {
        perror("shm_open");
        exit(EXIT_FAILURE);
    }

    /* Use fstat() to find the current size */
    if (fstat(fd, &sb) == -1) {
        perror("fstat");
        exit(EXIT_FAILURE);
    }

    printf("Opened %s, size = %ld bytes\n", SHM_NAME, (long)sb.st_size);

    /* Use fd with mmap() — see next tutorial */
    close(fd);

    return 0;
}

Note: fstat() works on the fd returned by shm_open() just like it does on a regular file fd. This is one of the advantages of the POSIX interface — standard tools work on shared memory.

Standard File Operations That Work on shm fd

Because shm_open() returns a regular fd, many standard system calls work on it:

Operation Use case on shm fd
fstat(fd, &sb) Get current size, permissions, timestamps
fchmod(fd, mode) Change access permissions
ftruncate(fd, size) Set or resize the object
mmap(NULL, size, ..., fd, 0) Map into address space
close(fd) Close fd (mapping stays valid)

Common Errors from shm_open()
errno Meaning Fix
ENOENT Object doesn’t exist and O_CREAT not set Add O_CREAT or run creator first
EEXIST O_CREAT | O_EXCL but object exists shm_unlink() first, or remove O_EXCL
EACCES No permission to open Check object permissions with ls /dev/shm
EINVAL Name is “/” or empty Use valid name like “/myobj”
EMFILE Process fd limit reached Close unused fds

Interview Questions — shm_open()

Q1. What does shm_open() return and how is it used?

It returns a file descriptor, just like open(). This fd is then passed to ftruncate() to set the size and to mmap() to map the object. After mapping, the fd can be closed.

Q2. What is the initial size of a newly created shared memory object?

Zero bytes. You must call ftruncate(fd, size) to make it usable. Trying to mmap() a zero-size object will fail with EINVAL.

Q3. What is the difference between O_CREAT alone versus O_CREAT | O_EXCL?

O_CREAT alone creates the object if it doesn’t exist but silently succeeds if it already exists. O_CREAT | O_EXCL fails with EEXIST if the object already exists — it guarantees the caller is the creator.

Q4. Can you use read() and write() on the fd returned by shm_open()?

Technically yes on Linux, but this defeats the purpose. Shared memory is useful because you use mmap() and then access data directly as memory — pointer dereferences — without any system calls for the actual data transfer.

Q5. What happens if two processes both call shm_open with O_CREAT for the same name?

Both succeed — the second call opens the existing object. The size set by the first caller is preserved. If you want to detect a race, use O_CREAT | O_EXCL, which makes only one process succeed.

Q6. After closing the fd from shm_open(), does the mapping created by mmap() remain valid?

Yes. The mmap() call adds a reference to the underlying shared memory object. Closing the fd reduces the file descriptor count but does not destroy the mapping. The mapping stays valid until munmap() is called.

Leave a Reply

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