| .\" Copyright 1993 Giorgio Ciucci (giorgio@crcc.it) |
| .\" and Copyright 2020 Michael Kerrisk <mtk.manpages@gmail.com> |
| .\" |
| .\" %%%LICENSE_START(VERBATIM) |
| .\" Permission is granted to make and distribute verbatim copies of this |
| .\" manual provided the copyright notice and this permission notice are |
| .\" preserved on all copies. |
| .\" |
| .\" Permission is granted to copy and distribute modified versions of this |
| .\" manual under the conditions for verbatim copying, provided that the |
| .\" entire resulting derived work is distributed under the terms of a |
| .\" permission notice identical to this one. |
| .\" |
| .\" Since the Linux kernel and libraries are constantly changing, this |
| .\" manual page may be incorrect or out-of-date. The author(s) assume no |
| .\" responsibility for errors or omissions, or for damages resulting from |
| .\" the use of the information contained herein. The author(s) may not |
| .\" have taken the same level of care in the production of this manual, |
| .\" which is licensed free of charge, as they might when working |
| .\" professionally. |
| .\" |
| .\" Formatted or processed versions of this manual, if unaccompanied by |
| .\" the source, must acknowledge the copyright and authors of this work. |
| .\" %%%LICENSE_END |
| .\" |
| .\" Modified Sun Nov 28 17:06:19 1993, Rik Faith (faith@cs.unc.edu) |
| .\" with material from Luigi P. Bai (lpb@softint.com) |
| .\" Portions Copyright 1993 Luigi P. Bai |
| .\" Modified Tue Oct 22 22:04:23 1996 by Eric S. Raymond <esr@thyrsus.com> |
| .\" Modified, 5 Jan 2002, Michael Kerrisk <mtk.manpages@gmail.com> |
| .\" Modified, 19 Sep 2002, Michael Kerrisk <mtk.manpages@gmail.com> |
| .\" Added SHM_REMAP flag description |
| .\" Modified, 27 May 2004, Michael Kerrisk <mtk.manpages@gmail.com> |
| .\" Added notes on capability requirements |
| .\" Modified, 11 Nov 2004, Michael Kerrisk <mtk.manpages@gmail.com> |
| .\" Language and formatting clean-ups |
| .\" Changed wording and placement of sentence regarding attachment |
| .\" of segments marked for destruction |
| .\" |
| .TH SHMOP 2 2021-03-22 "Linux" "Linux Programmer's Manual" |
| .SH NAME |
| shmat, shmdt \- System V shared memory operations |
| .SH SYNOPSIS |
| .nf |
| .B #include <sys/types.h> |
| .B #include <sys/shm.h> |
| .PP |
| .BI "void *shmat(int " shmid ", const void *" shmaddr ", int " shmflg ); |
| .BI "int shmdt(const void *" shmaddr ); |
| .fi |
| .SH DESCRIPTION |
| .SS shmat() |
| .BR shmat () |
| attaches the System\ V shared memory segment identified by |
| .I shmid |
| to the address space of the calling process. |
| The attaching address is specified by |
| .I shmaddr |
| with one of the following criteria: |
| .IP \(bu 2 |
| If |
| .I shmaddr |
| is NULL, |
| the system chooses a suitable (unused) page-aligned address to attach |
| the segment. |
| .IP \(bu |
| If |
| .I shmaddr |
| isn't NULL |
| and |
| .B SHM_RND |
| is specified in |
| .IR shmflg , |
| the attach occurs at the address equal to |
| .I shmaddr |
| rounded down to the nearest multiple of |
| .BR SHMLBA . |
| .IP \(bu |
| Otherwise, |
| .I shmaddr |
| must be a page-aligned address at which the attach occurs. |
| .PP |
| In addition to |
| .BR SHM_RND , |
| the following flags may be specified in the |
| .I shmflg |
| bit-mask argument: |
| .TP |
| .BR SHM_EXEC " (Linux-specific; since Linux 2.6.9)" |
| Allow the contents of the segment to be executed. |
| The caller must have execute permission on the segment. |
| .TP |
| .BR SHM_RDONLY |
| Attach the segment for read-only access. |
| The process must have read permission for the segment. |
| If this flag is not specified, |
| the segment is attached for read and write access, |
| and the process must have read and write permission for the segment. |
| There is no notion of a write-only shared memory segment. |
| .TP |
| .BR SHM_REMAP " (Linux-specific)" |
| This flag specifies |
| that the mapping of the segment should replace |
| any existing mapping in the range starting at |
| .I shmaddr |
| and continuing for the size of the segment. |
| (Normally, an |
| .B EINVAL |
| error would result if a mapping already exists in this address range.) |
| In this case, |
| .I shmaddr |
| must not be NULL. |
| .PP |
| The |
| .BR brk (2) |
| value of the calling process is not altered by the attach. |
| The segment will automatically be detached at process exit. |
| The same segment may be attached as a read and as a read-write |
| one, and more than once, in the process's address space. |
| .PP |
| A successful |
| .BR shmat () |
| call updates the members of the |
| .I shmid_ds |
| structure (see |
| .BR shmctl (2)) |
| associated with the shared memory segment as follows: |
| .IP \(bu 2 |
| .I shm_atime |
| is set to the current time. |
| .IP \(bu |
| .I shm_lpid |
| is set to the process-ID of the calling process. |
| .IP \(bu |
| .I shm_nattch |
| is incremented by one. |
| .\" |
| .SS shmdt() |
| .BR shmdt () |
| detaches the shared memory segment located at the address specified by |
| .I shmaddr |
| from the address space of the calling process. |
| The to-be-detached segment must be currently |
| attached with |
| .I shmaddr |
| equal to the value returned by the attaching |
| .BR shmat () |
| call. |
| .PP |
| On a successful |
| .BR shmdt () |
| call, the system updates the members of the |
| .I shmid_ds |
| structure associated with the shared memory segment as follows: |
| .IP \(bu 2 |
| .I shm_dtime |
| is set to the current time. |
| .IP \(bu |
| .I shm_lpid |
| is set to the process-ID of the calling process. |
| .IP \(bu |
| .I shm_nattch |
| is decremented by one. |
| If it becomes 0 and the segment is marked for deletion, |
| the segment is deleted. |
| .SH RETURN VALUE |
| On success, |
| .BR shmat () |
| returns the address of the attached shared memory segment; on error, |
| .I (void\ *)\ \-1 |
| is returned, and |
| .I errno |
| is set to indicate the error. |
| .PP |
| On success, |
| .BR shmdt () |
| returns 0; on error \-1 is returned, and |
| .I errno |
| is set to indicate the error. |
| .SH ERRORS |
| .BR shmat () |
| can fail with one of the following errors: |
| .TP |
| .B EACCES |
| The calling process does not have the required permissions for |
| the requested attach type, and does not have the |
| .B CAP_IPC_OWNER |
| capability in the user namespace that governs its IPC namespace. |
| .TP |
| .B EIDRM |
| \fIshmid\fP points to a removed identifier. |
| .TP |
| .B EINVAL |
| Invalid |
| .I shmid |
| value, unaligned (i.e., not page-aligned and \fBSHM_RND\fP was not |
| specified) or invalid |
| .I shmaddr |
| value, or can't attach segment at |
| .IR shmaddr , |
| or |
| .B SHM_REMAP |
| was specified and |
| .I shmaddr |
| was NULL. |
| .TP |
| .B ENOMEM |
| Could not allocate memory for the descriptor or for the page tables. |
| .PP |
| .BR shmdt () |
| .I errno |
| can fail with one of the following errors: |
| .TP |
| .B EINVAL |
| There is no shared memory segment attached at |
| .IR shmaddr ; |
| or, |
| .\" The following since 2.6.17-rc1: |
| .I shmaddr |
| is not aligned on a page boundary. |
| .SH CONFORMING TO |
| POSIX.1-2001, POSIX.1-2008, SVr4. |
| .\" SVr4 documents an additional error condition EMFILE. |
| .PP |
| In SVID 3 (or perhaps earlier), |
| the type of the \fIshmaddr\fP argument was changed from |
| .I "char\ *" |
| into |
| .IR "const void\ *" , |
| and the returned type of |
| .BR shmat () |
| from |
| .I "char\ *" |
| into |
| .IR "void\ *" . |
| .SH NOTES |
| After a |
| .BR fork (2), |
| the child inherits the attached shared memory segments. |
| .PP |
| After an |
| .BR execve (2), |
| all attached shared memory segments are detached from the process. |
| .PP |
| Upon |
| .BR _exit (2), |
| all attached shared memory segments are detached from the process. |
| .PP |
| Using |
| .BR shmat () |
| with |
| .I shmaddr |
| equal to NULL |
| is the preferred, portable way of attaching a shared memory segment. |
| Be aware that the shared memory segment attached in this way |
| may be attached at different addresses in different processes. |
| Therefore, any pointers maintained within the shared memory must be |
| made relative (typically to the starting address of the segment), |
| rather than absolute. |
| .PP |
| On Linux, it is possible to attach a shared memory segment even if it |
| is already marked to be deleted. |
| However, POSIX.1 does not specify this behavior and |
| many other implementations do not support it. |
| .PP |
| The following system parameter affects |
| .BR shmat (): |
| .TP |
| .B SHMLBA |
| Segment low boundary address multiple. |
| When explicitly specifying an attach address in a call to |
| .BR shmat (), |
| the caller should ensure that the address is a multiple of this value. |
| This is necessary on some architectures, |
| in order either to ensure good CPU cache performance or to ensure that |
| different attaches of the same segment have consistent views |
| within the CPU cache. |
| .B SHMLBA |
| is normally some multiple of the system page size. |
| (On many Linux architectures, |
| .B SHMLBA |
| is the same as the system page size.) |
| .PP |
| The implementation places no intrinsic per-process limit on the |
| number of shared memory segments |
| .RB ( SHMSEG ). |
| .SH EXAMPLES |
| The two programs shown below exchange a string using a shared memory segment. |
| Further details about the programs are given below. |
| First, we show a shell session demonstrating their use. |
| .PP |
| In one terminal window, we run the "reader" program, |
| which creates a System V shared memory segment and a System V semaphore set. |
| The program prints out the IDs of the created objects, |
| and then waits for the semaphore to change value. |
| .PP |
| .in +4n |
| .EX |
| $ \fB./svshm_string_read\fP |
| shmid = 1114194; semid = 15 |
| .EE |
| .in |
| .PP |
| In another terminal window, we run the "writer" program. |
| The "writer" program takes three command-line arguments: |
| the IDs of the shared memory segment and semaphore set created |
| by the "reader", and a string. |
| It attaches the existing shared memory segment, |
| copies the string to the shared memory, and modifies the semaphore value. |
| .PP |
| .in +4n |
| .EX |
| $ \fB./svshm_string_write 1114194 15 \(aqHello, world\(aq\fP |
| .EE |
| .in |
| .PP |
| Returning to the terminal where the "reader" is running, |
| we see that the program has ceased waiting on the semaphore |
| and has printed the string that was copied into the |
| shared memory segment by the writer: |
| .PP |
| .in +4n |
| .EX |
| Hello, world |
| .EE |
| .in |
| .\" |
| .SS Program source: svshm_string.h |
| The following header file is included by the "reader" and "writer" programs. |
| .PP |
| .in +4n |
| .EX |
| #include <sys/types.h> |
| #include <sys/ipc.h> |
| #include <sys/shm.h> |
| #include <sys/sem.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \e |
| } while (0) |
| |
| 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 |
| .EE |
| .in |
| .\" |
| .SS Program source: svshm_string_read.c |
| The "reader" program creates a shared memory segment and a semaphore set |
| containing one semaphore. |
| It then attaches the shared memory object into its address space |
| and initializes the semaphore value to 1. |
| Finally, the program waits for the semaphore value to become 0, |
| and afterwards prints the string that has been copied into the |
| shared memory segment by the "writer". |
| .PP |
| .in +4n |
| .EX |
| /* svshm_string_read.c |
| |
| Licensed under GNU General Public License v2 or later. |
| */ |
| #include "svshm_string.h" |
| |
| int |
| main(int argc, char *argv[]) |
| { |
| int semid, shmid; |
| union semun arg, dummy; |
| struct sembuf sop; |
| char *addr; |
| |
| /* Create shared memory and semaphore set containing one |
| semaphore. */ |
| |
| shmid = shmget(IPC_PRIVATE, MEM_SIZE, IPC_CREAT | 0600); |
| if (shmid == \-1) |
| errExit("shmget"); |
| |
| semid = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600); |
| if (shmid == \-1) |
| errExit("shmget"); |
| |
| /* Attach shared memory into our address space. */ |
| |
| addr = shmat(shmid, NULL, SHM_RDONLY); |
| if (addr == (void *) \-1) |
| errExit("shmat"); |
| |
| /* Initialize semaphore 0 in set with value 1. */ |
| |
| arg.val = 1; |
| if (semctl(semid, 0, SETVAL, arg) == \-1) |
| errExit("semctl"); |
| |
| printf("shmid = %d; semid = %d\en", shmid, 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) |
| errExit("semop"); |
| |
| /* Print the string from shared memory. */ |
| |
| printf("%s\en", addr); |
| |
| /* Remove shared memory and semaphore set. */ |
| |
| if (shmctl(shmid, IPC_RMID, NULL) == \-1) |
| errExit("shmctl"); |
| if (semctl(semid, 0, IPC_RMID, dummy) == \-1) |
| errExit("semctl"); |
| |
| exit(EXIT_SUCCESS); |
| } |
| .EE |
| .in |
| .\" |
| .SS 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 have already been created by the "reader", and a string. |
| It attaches the shared memory segment into its address space, |
| and then decrements the semaphore value to 0 in order to inform the |
| "reader" that it can now examine the contents of the shared memory. |
| .PP |
| .in +4n |
| .EX |
| /* svshm_string_write.c |
| |
| Licensed under GNU General Public License v2 or later. |
| */ |
| #include "svshm_string.h" |
| |
| int |
| main(int argc, char *argv[]) |
| { |
| int semid, shmid; |
| struct sembuf sop; |
| char *addr; |
| size_t len; |
| |
| if (argc != 4) { |
| fprintf(stderr, "Usage: %s shmid semid string\en", argv[0]); |
| exit(EXIT_FAILURE); |
| } |
| |
| len = strlen(argv[3]) + 1; /* +1 to include trailing \(aq\e0\(aq */ |
| if (len > MEM_SIZE) { |
| fprintf(stderr, "String is too big!\en"); |
| 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) |
| errExit("shmat"); |
| |
| memcpy(addr, argv[3], len); |
| |
| /* Decrement semaphore to 0. */ |
| |
| sop.sem_num = 0; |
| sop.sem_op = \-1; |
| sop.sem_flg = 0; |
| |
| if (semop(semid, &sop, 1) == \-1) |
| errExit("semop"); |
| |
| exit(EXIT_SUCCESS); |
| } |
| .EE |
| .in |
| .SH SEE ALSO |
| .BR brk (2), |
| .BR mmap (2), |
| .BR shmctl (2), |
| .BR shmget (2), |
| .BR capabilities (7), |
| .BR shm_overview (7), |
| .BR sysvipc (7) |