SHMOP(2)
๐ SHMOP(2) โ the <sys/shm.h> bestie era ๐
okay so. this is the manual page for shmat and shmdt, from section 2 of the manual (system calls, iykyk). System V shared memory operations, babes. Let's get into it โจ
๐ธ NAME ๐ธ
shmat, shmdt โ System V shared memory operations
๐ LIBRARY ๐
Standard C library (libc, <cyan>-lc`)
๐ฆ SYNOPSIS ๐ฆ
#include <sys/shm.h>
void *shmat(int shmid, const void *_Nullable shmaddr, int shmflg);
int shmdt(const void *shmaddr);
๐ DESCRIPTION ๐
โจ shmat() โจ
So shmat() attaches the System V shared memory segment that's identified by shmid onto the address space of the process that's calling it. literally moving in, no paperwork.
Where it lands is decided by shmaddr, and there are three (3) whole scenarios, pick your fighter:
- If
shmaddrisNULL, the system picks a suitable (unused) page-aligned address to attach the segment at. it's giving "you choose, king". ๐ - If
shmaddris notNULLandSHM_RNDis specified inshmflg, the attach happens at the address equal toshmaddrrounded down to the nearest multiple ofSHMLBA. - Otherwise,
shmaddrmust be a page-aligned address, and that's where the attach occurs. no rounding, no mercy. ๐
On top of SHM_RND, you can also pass these flags in the shmflg bit-mask argument:
SHM_EXECโ Linux-specific; since Linux 2.6.9 โ lets the contents of the segment be executed. the caller must have execute permission on the segment. main character energy fr fr ๐ฅSHM_RDONLYโ attach the segment for read-only access. the process must have read permission for the segment. if you don't pass this flag, the segment gets attached for read and write access, and the process must have read and write permission for the segment. and bestie, there is no notion of a write-only shared memory segment. it does not exist. periodt.SHM_REMAPโ Linux-specific โ this one says the mapping of the segment should replace any existing mapping in the range starting atshmaddrand continuing for the size of the segment. (Normally you'd get anEINVALerror if a mapping already existed in that address range โ so this is you saying "yeah I know, do it anyway".) In this case,shmaddrmust not beNULL. no cap.
The brk(2) value of the calling process is not altered by the attach. the segment will automatically be detached at process exit. and the same segment can be attached as a read one and as a read-write one, and more than once, in the process's address space. it contains multitudes ๐ฆ
A successful shmat() call updates the members of the shmid_ds structure (see shmctl(2)) associated with the shared memory segment, like this:
shm_atimeis set to the current time. โฐshm_lpidis set to the process-ID of the calling process.shm_nattchis incremented by one.
โจ shmdt() โจ
shmdt() does the opposite vibe: it detaches the shared memory segment located at the address specified by shmaddr from the address space of the calling process. moving out, sending the goodbye text. ๐ญ
The segment you're detaching must currently be attached with shmaddr equal to the value that the attaching shmat() call returned. like, you have to use the exact address it gave you, no improvising.
On a successful shmdt() call, the system updates the members of the shmid_ds structure associated with the shared memory segment, like this:
shm_dtimeis set to the current time. โฐshm_lpidis set to the process-ID of the calling process.shm_nattchis decremented by one. and if it becomes0and the segment is marked for deletion, the segment is deleted. gone, reduced to atoms ๐โจ
๐ RETURN VALUE ๐
On success, shmat() returns the address of the attached shared memory segment. on error, it returns (void *) -1, and errno is set to indicate the error.
On success, shmdt() returns 0. on error, it returns -1, and errno is set to indicate the error. ๐
๐ฅ ERRORS ๐ฅ
shmat() can fail with one of the following errors:
EACCESโ the calling process doesn't have the required permissions for the requested attach type, and doesn't have theCAP_IPC_OWNERcapability in the user namespace that governs its IPC namespace. permission denied, bestie, not your era ๐EIDRMโshmidpoints to a removed identifier.EINVALโ invalidshmidvalue; or unaligned (i.e., not page-aligned andSHM_RNDwas not specified); or invalidshmaddrvalue; or can't attach the segment atshmaddr; orSHM_REMAPwas specified andshmaddrwasNULL. so many ways to be invalid, it's honestly iconic ๐ญENOMEMโ could not allocate memory for the descriptor or for the page tables.
shmdt() can fail with one of the following errors:
EINVALโ there's no shared memory segment attached atshmaddr; or,shmaddrisn't aligned on a page boundary.
๐ STANDARDS ๐
POSIX.1-2008.
๐ HISTORY ๐
POSIX.1-2001, SVr4.
In SVID 3 (or maybe even earlier), the type of the shmaddr argument was changed from char * into const void *, and the returned type of shmat() went from char * into void *. glow-up, honestly. โจ
POSIX.1-2024 changed the error code from (void *) -1 to SHM_FAILED. the old way is giving vintage, the new way is giving modern.
๐ง NOTES ๐ง
- After a
fork(2), the child inherits the attached shared memory segments. family heirloom ๐ซถ - After an
execve(2), all attached shared memory segments are detached from the process. - Upon
_exit(3), all attached shared memory segments are detached from the process.
Using shmat() with shmaddr equal to NULL is the preferred, portable way of attaching a shared memory segment. but be aware: the shared memory segment attached this way may end up attached at different addresses in different processes. so any pointers you keep inside that shared memory have to be made relative (typically to the starting address of the segment), rather than absolute. do not hardcode addresses, I am begging ๐
On Linux, it's possible to attach a shared memory segment even if it's already marked to be deleted. however, POSIX.1 does not specify this behavior, and many other implementations don't support it. so like, it's a Linux thing, don't build your whole personality on it.
The following system parameter affects shmat():
SHMLBAโ Segment low boundary address multiple. When you're explicitly specifying an attach address in a call toshmat(), the caller should make sure the address is a multiple of this value. This is necessary on some architectures, either to ensure good CPU cache performance, or to ensure that different attaches of the same segment have consistent views within the CPU cache.SHMLBAis normally some multiple of the system page size. (On many Linux architectures,SHMLBAis the same as the system page size.)
The implementation places no intrinsic per-process limit on the number of shared memory segments (SHMSEG). go off, attach as many as your heart desires ๐
โญ and that's part 1, bestie โ hold on, there's more coming, don't go anywhere โญ
โจ EXAMPLES โจ
okay bestie this is the FUN part ๐ญ๐ two lil baby programs passing a string back and forth through a shared memory segment, like besties swapping notes in class but the note is literally bytes in kernel memory. Details below, but first โ a shell session showing the whole thing in action โจ
In one terminal window, we run the "reader" program, which creates a System V shared memory segment and a System V semaphore set. It prints out the IDs of the objects it made, then justโฆ waits ๐ซถ waits for the semaphore to change value. main character behaviour honestly.
$ ./svshm_string_read;
shmid = 1114194
semid = 15
In another terminal window, we run the "writer" program. She takes three command-line arguments: the IDs of the shared memory segment and semaphore set created by the "reader", plus a string. She attaches the existing shared memory segment, copies the string into shared memory, and modifies the semaphore value. slay ๐
$ ./svshm_string_write 1114194 15 'Hello, world';
Now back to the terminal where the "reader" is vibing โ we see she's stopped waiting on the semaphore and has printed the string that the writer copied into the shared memory segment:
Hello, world
๐ธ Program source: svshm_string.h ๐ธ
This header file gets included by both the "reader" and "writer" programs, no cap:
/* svshm_string.h
Licensed under GNU General Public License v2 or later.
*/
#ifndef SVSHM_STRING_H
#define SVSHM_STRING_H
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/sem.h>
union semun { /* Used in calls to semctl() */
int val;
struct semid_ds *buf;
unsigned short *array;
#if defined(__linux__)
struct seminfo *__buf;
#endif
};
#define MEM_SIZE 4096
#endif // include guard
๐ฆ Program source: svshm_string_read.c ๐ฆ
The "reader" program creates a shared memory segment and a semaphore set containing one semaphore. Then she attaches the shared memory object into her address space and initializes the semaphore value to 1. Finally โ the iconique part โ she waits for the semaphore value to become 0, and afterwards prints the string that the "writer" copied into the shared memory segment. patience is a flex fr fr ๐
/* svshm_string_read.c
Licensed under GNU General Public License v2 or later.
*/
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include "svshm_string.h"
int
main(void)
{
int semid, shmid;
char *addr;
union semun arg, dummy;
struct sembuf sop;
/* Create shared memory and semaphore set containing one
semaphore. */
shmid = shmget(IPC_PRIVATE, MEM_SIZE, IPC_CREAT | 0600);
if (shmid == -1)
err(EXIT_FAILURE, "shmget");
semid = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600);
if (semid == -1)
err(EXIT_FAILURE, "semget");
/* Attach shared memory into our address space. */
addr = shmat(shmid, NULL, SHM_RDONLY);
if (addr == (void *) -1)
err(EXIT_FAILURE, "shmat");
/* Initialize semaphore 0 in set with value 1. */
arg.val = 1;
if (semctl(semid, 0, SETVAL, arg) == -1)
err(EXIT_FAILURE, "semctl");
printf("shmid = %d\n", shmid);
printf("semid = %d\n", semid);
/* Wait for semaphore value to become 0. */
sop.sem_num = 0;
sop.sem_op = 0;
sop.sem_flg = 0;
if (semop(semid, &sop, 1) == -1)
err(EXIT_FAILURE, "semop");
/* Print the string from shared memory. */
printf("%s\n", addr);
/* Remove shared memory and semaphore set. */
if (shmctl(shmid, IPC_RMID, NULL) == -1)
err(EXIT_FAILURE, "shmctl");
if (semctl(semid, 0, IPC_RMID, dummy) == -1)
err(EXIT_FAILURE, "semctl");
exit(EXIT_SUCCESS);
}
๐ Program source: svshm_string_write.c ๐
The writer program takes three command-line arguments: the IDs of the shared memory segment and semaphore set that were already created by the "reader", plus a string. She attaches the shared memory segment into her address space, and then decrements the semaphore value to 0 to let the "reader" know that she can now go examine the contents of shared memory. the way that she justโฆ signals. communication queen ๐
/* svshm_string_write.c
Licensed under GNU General Public License v2 or later.
*/
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include "svshm_string.h"
int
main(int argc, char *argv[])
{
int semid, shmid;
char *addr;
size_t size;
struct sembuf sop;
if (argc != 4) {
fprintf(stderr, "Usage: %s shmid semid string\n", argv[0]);
exit(EXIT_FAILURE);
}
size = strlen(argv[3]) + 1; /* +1 to include trailing '\0' */
if (size > MEM_SIZE) {
fprintf(stderr, "String is too big!\n");
exit(EXIT_FAILURE);
}
/* Get object IDs from command-line. */
shmid = atoi(argv[1]);
semid = atoi(argv[2]);
/* Attach shared memory into our address space and copy string
(including trailing null byte) into memory. */
addr = shmat(shmid, NULL, 0);
if (addr == (void *) -1)
err(EXIT_FAILURE, "shmat");
memcpy(addr, argv[3], size);
/* Decrement semaphore to 0. */
sop.sem_num = 0;
sop.sem_op = -1;
sop.sem_flg = 0;
if (semop(semid, &sop, 1) == -1)
err(EXIT_FAILURE, "semop");
exit(EXIT_SUCCESS);
}
๐ SEE ALSO ๐
go read these next bestie, the lore is DEEP:
and that's the whole page bestie!! ๐ซถโจ this one came from Linux man-pages 6.20, dated 2026-06-05, and it's page SHMOP(2) in case you need to cite it in your essay ๐
๐ go share some memory responsibly, drink water, and don't forget to shmdt() before you leave. mwah ๐๐
๐ฆ where this page comes from
- arch rolling: man-pages 6.20-1 ยท BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
- nixpkgs unstable: man-pages 6.20
- ๐ the page's license: Linux-man-pages-copyleft
- Copyright 1993, Giorgio Ciucci <giorgio@crcc.it>
- Copyright 2020, Michael Kerrisk <mtk.manpages@gmail.com>
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms