mirror of https://github.com/mkerrisk/man-pages
511 lines
13 KiB
Groff
511 lines
13 KiB
Groff
.\" 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 2020-04-11 "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 );
|
|
.PP
|
|
.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 cause of the error.
|
|
.PP
|
|
On success,
|
|
.BR shmdt ()
|
|
returns 0; on error \-1 is returned, and
|
|
.I errno
|
|
is set to indicate the cause of the error.
|
|
.SH ERRORS
|
|
When
|
|
.BR shmat ()
|
|
fails,
|
|
.I errno
|
|
is set to one of the following:
|
|
.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
|
|
When
|
|
.BR shmdt ()
|
|
fails,
|
|
.I errno
|
|
is set as follows:
|
|
.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
|
|
.PP
|
|
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 EXAMPLE
|
|
.PP
|
|
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
|
|
.PP
|
|
.\"
|
|
.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 t0 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)
|