The shm_open() function is declared in <sys/mman.h>:
#include <fcntl.h> /* Defines O_* constants */
#include <sys/stat.h> /* Defines mode constants */
#include <sys/mman.h>
int shm_open(const char *name, int oflag, mode_t mode);
/* Returns: file descriptor on success, -1 on error */
The three arguments are deliberately modeled after open(): a name, flags, and permissions. If you already know how to call open(), you mostly know how to call shm_open().
The name argument identifies the shared memory object. POSIX.1 defines portable naming rules that you should always follow:
/, followed by one or more characters with no additional //, or contains additional / characters in the name/dev/shm/. So /myshm appears as /dev/shm/myshm. You can verify this with ls -l /dev/shm after creation.The oflag argument is a bitmask that controls two things: (a) whether you are creating a new object or opening an existing one, and (b) the access mode. You must specify exactly one access mode flag.
| Flag | Category | Meaning |
|---|---|---|
O_CREAT |
Creation | Create the object if it doesn’t exist. If it exists, just open it (no error). |
O_EXCL |
Creation | Used with O_CREAT: fail with EEXIST if object already exists. Guarantees you are the creator. |
O_RDONLY |
Access (required) | Open for read-only access. The resulting mmap() can only use PROT_READ. |
O_RDWR |
Access (required) | Open for read-write access. Required if the process will write to shared memory. |
O_TRUNC |
Modification | Truncate the object to zero length on open (if the object already exists). Use carefully. |
The mode argument specifies the file permission bits when creating a new object. It is exactly the same as the mode bits used for regular files (see stat(2)).
If you are not creating a new object (i.e., O_CREAT is absent from oflag), you should pass 0 for mode โ it is ignored in that case.
/* Common permission values for shm_open() */
fd = shm_open("/myshm", O_CREAT | O_RDWR, 0600);
/* ^^^^
* 0600 = owner read + write
* 0660 = owner + group read + write
* 0644 = owner read+write, others read-only
*
* The actual permissions are further masked by the
* process's umask, just like open().
*/
/* Opening an existing object (no creation) */
fd = shm_open("/myshm", O_RDONLY, 0);
/* ^ pass 0 when not creating */
open()).The file descriptor returned by shm_open() always has the FD_CLOEXEC flag set automatically. This means:
If the process calls exec() to replace its image with a new program, the shared memory file descriptor is automatically closed. The new program does not inherit it.
This is consistent with the behavior of memory mappings: exec() unmaps all memory mappings of the old process. So there is no point in the new program having the fd. This prevents accidental fd leaks into child processes.
This example shows two processes: a creator (uses O_CREAT | O_EXCL) and a consumer (opens existing object with O_RDONLY).
/*
* shm_creator.c โ Creates a shared memory object exclusively
* Compile: gcc shm_creator.c -o shm_creator -lrt
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#define SHM_NAME "/ep_channel"
#define SHM_SIZE 1024
int main(void)
{
int fd;
char *addr;
/*
* O_CREAT | O_EXCL | O_RDWR:
* - Create the object (O_CREAT)
* - Fail if already exists (O_EXCL) โ we want to be the only creator
* - Open for read-write (O_RDWR)
* 0660: owner and group can read/write
*/
fd = shm_open(SHM_NAME, O_CREAT | O_EXCL | O_RDWR, 0660);
if (fd == -1) {
if (errno == EEXIST) {
fprintf(stderr,
"Shared memory '%s' already exists. "
"Run: shm_unlink %s or rm /dev/shm%s\n",
SHM_NAME, SHM_NAME, SHM_NAME);
} else {
perror("shm_open");
}
exit(EXIT_FAILURE);
}
printf("[Creator] shm_open() OK. fd=%d\n", fd);
/* Set the size before any mmap() */
if (ftruncate(fd, SHM_SIZE) == -1) {
perror("ftruncate");
shm_unlink(SHM_NAME);
exit(EXIT_FAILURE);
}
/* Map it */
addr = mmap(NULL, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED) {
perror("mmap");
shm_unlink(SHM_NAME);
exit(EXIT_FAILURE);
}
close(fd); /* fd not needed after mmap */
/* Write a message */
snprintf(addr, SHM_SIZE, "Message from creator: pid=%d", (int)getpid());
printf("[Creator] Wrote: %s\n", addr);
printf("[Creator] Run shm_reader now. Press Enter to cleanup...\n");
getchar();
munmap(addr, SHM_SIZE);
shm_unlink(SHM_NAME);
printf("[Creator] Cleaned up.\n");
return 0;
}
/*
* shm_reader.c โ Opens an existing shared memory object read-only
* Compile: gcc shm_reader.c -o shm_reader -lrt
* Run AFTER shm_creator is running.
*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#define SHM_NAME "/ep_channel"
#define SHM_SIZE 1024
int main(void)
{
int fd;
char *addr;
/*
* O_RDONLY: open existing object for reading only
* mode = 0: not creating, so mode is ignored
*/
fd = shm_open(SHM_NAME, O_RDONLY, 0);
if (fd == -1) {
perror("shm_open");
exit(EXIT_FAILURE);
}
printf("[Reader] shm_open() OK. fd=%d\n", fd);
/* Map read-only: PROT_READ only (matching O_RDONLY) */
addr = mmap(NULL, SHM_SIZE, PROT_READ, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED) {
perror("mmap");
exit(EXIT_FAILURE);
}
close(fd);
printf("[Reader] Read: %s\n", addr);
munmap(addr, SHM_SIZE);
return 0;
}
# Terminal 1
gcc shm_creator.c -o shm_creator -lrt
./shm_creator
# Terminal 2 (while creator is waiting)
gcc shm_reader.c -o shm_reader -lrt
./shm_reader
# Press Enter in Terminal 1 to cleanup
Specifying O_TRUNC when opening an existing shared memory object truncates it to zero length immediately. This destroys any existing data.
/* O_TRUNC: opens the existing object and resets its size to 0 */
fd = shm_open("/myshm", O_RDWR | O_TRUNC, 0);
/*
* After this call:
* - The object exists but has size 0
* - Any processes that had it mapped still have their mapping
* but the backing region was shrunk โ accessing beyond the
* new end results in SIGBUS
* - You must call ftruncate() again to restore a usable size
*
* Linux note: O_TRUNC works even with O_RDONLY (read-only open),
* but this is undefined behavior per POSIX โ avoid it.
*/
O_TRUNC combined with O_RDONLY is undefined. On Linux it truncates anyway, but do not rely on this in portable code./), followed by one or more characters, none of which are additional /. So /myshm is valid, but myshm (no leading slash) and /my/shm (extra slash) are not portably valid.O_CREAT alone creates the object if it does not exist; if it already exists, it simply opens it (no error). O_CREAT | O_EXCL guarantees the caller is the creator โ if the object already exists, the call fails with EEXIST. Use O_EXCL when you need exclusive ownership of the creation.exec(), all memory mappings are unmapped. Keeping the file descriptor open in the new program’s image would be useless at best and a resource leak at worst. Setting FD_CLOEXEC ensures automatic closure, preventing accidental inheritance by exec’d children.0. The mode argument is only used when O_CREAT is in oflag. When you are only opening an existing object, the mode value is ignored, so passing 0 makes the intent clear.O_RDONLY and maps with PROT_READ; another opens with O_RDWR and maps with PROT_READ | PROT_WRITE. Both refer to the same underlying object. The writer’s changes are immediately visible to the reader because both map the same physical pages (via MAP_SHARED).<fcntl.h> (for O_CREAT, O_RDWR, etc.), <sys/stat.h> (for mode constants like S_IRUSR), and <sys/mman.h> (for the shm_open() prototype itself).-1 and sets errno to EEXIST (error: “File exists”). Your code should check for this specific error if you want to handle the “already created by another process” case gracefully.