0% found this document useful (0 votes)
5 views64 pages

CS10

Uploaded by

jarison_mander
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views64 pages

CS10

Uploaded by

jarison_mander
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 64

Contact Session-10

IPC Using Shared Memory


Introduction
• Shared memory allows two or more processes to share the same region
(usually referred to as a segment) of physical memory.
• Since a shared memory segment becomes part of a process’s user-space
memory, no kernel intervention is required for IPC.
• One process copies data into the shared memory; that data is immediately
available to all other processes sharing the same segment.
• This provides fast IPC by comparison with techniques such as pipes or
message queues, where the sending process copies data from a buffer in
user space into kernel memory and the receiving process copies in the
reverse direction. (Each process also incurs the overhead of a system call to
perform the copy operation.)
• On the other hand, the fact that IPC using shared memory is not mediated by
the kernel means that, typically, some method of synchronization is required
so that processes don’t simultaneously access the shared memory (e.g., two
processes performing simultaneous updates, or one process fetching data
from the shared memory while another process is in the middle of updating
it). System V semaphores are a natural method for such synchronization.
Overview
In order to use a shared memory segment, we typically perform the following
steps:
 Call shmget() to create a new shared memory segment or obtain the
identifier of an existing segment (i.e., one created by another process).
 Use shmat() to attach the shared memory segment; that is, make the
segment part of the virtual memory of the calling process.
 At this point, the shared memory segment can be treated just like any other
memory available to the program. In order to refer to the shared memory,
the program uses the addr value returned by the shmat() call, which is a
pointer to the start of the shared memory segment in the process’s virtual
address space.
 Call shmdt() to detach the shared memory segment. After this call, the
process can no longer refer to the shared memory. This step is optional, and
happens automatically on process termination.
 Call shmctl() to delete the shared memory segment. The segment will be
destroyed only after all currently attached processes have detached it. Only
one process needs to perform this step.
Creating or Opening a Shared Memory
Segment
• The shmget() system call creates a new shared
memory segment or obtains the identifier of an
existing segment. The contents of a newly created
shared memory segment are initialized to 0.
#include <sys/types.h> /* For portability */
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
Returns shared memory segment identifier on
success, or –1 on error
• The key argument is a key generated using one of the
methods described in previous Section.
• size specifies a positive integer that indicates the desired
size of the segment, in bytes. The kernel allocates shared
memory in multiples of the system page size, so size is
effectively rounded up to the next multiple of the system
page size.
• If we are using shmget() to obtain the identifier of an
existing segment, then size has no effect on the segment,
but it must be less than or equal to the size of the
segment.
• The shmflg argument performs the same task as for the
other IPC get calls, specifying the permissions. In addition,
zero or more of the following flags can be ORed (|) in
shmflg to control the operation of shmget():
IPC_CREAT
• If no segment with the specified key exists,
create a new segment.
IPC_EXCL
• If IPC_CREAT was also specified, and a segment
with the specified key already exists, fail with
the error EEXIST.
Using Shared Memory
• The shmat() system call attaches the shared memory
segment identified by shmid to the calling process’s
virtual address space.
#include <sys/types.h> /* For portability */
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int
shmflg);
Returns address at which shared memory is attached on
success,
or (void *) –1 on error
• The shmaddr argument and the setting of the SHM_RND
bit in the shmflg bit-mask argument control how the
segment is attached:
If shmaddr is NULL, then the segment is attached at a
suitable address selected by the kernel. This is the
preferred method of attaching a segment.
If shmaddr is not NULL, and SHM_RND is not set, then the
segment is attached at the address specified by shmaddr,
which must be a multiple of the system page size (or the
error EINVAL results).
 If shmaddr is not NULL, and SHM_RND is set, then the
segment is mapped at the address provided in shmaddr,
rounded to the nearest multiple of the constant SHMLBA
(shared memory low boundary address).
Specifying a non-NULL value for shmaddr (i.e., either
the second or third option listed
above) is not recommended, for the following reasons:

 It reduces the portability of an application. An address valid


on one UNIX implementation may be invalid on another.

 An attempt to attach a shared memory segment at a particular


address will fail if that address is already in use. This could
happen if, for example, the application (perhaps inside a
library function) had already attached another.
• SHM_RDONLY
• To attach a shared memory segment for read-
only access, we specify the flag SHM_RDONLY in
shmflg.
• Attempts to update the contents of a read-only
segment results in a segmentation fault (the
SIGSEGV signal). If SHM_RDONLY is not specified,
the memory can be both read and modified.
• To attach a shared memory segment, a process
requires read and write permissions on the
segment, unless SHM_RDONLY is specified, in
which case only read permission is required.
• SHM_REMAP
• One final value that may be specified in shmflg is
SHM_REMAP.
• In this case, shmaddr must be non-NULL. This flag
requests that the shmat() call replace any existing
shared memory attachment or memory mapping
in the range starting at shmaddr and continuing
for the length of the shared memory segment.
• Normally, if we try to attach a shared memory
segment at an address range that is already in
use, the error EINVAL results. SHM_REMAP is a
nonstandard Linux extension.
Table summarizes the constants that can be
ORed in the shmflg argument
of shmat().
shmdt()
• When a process no longer needs to access a
shared memory segment, it can call shmdt() to
detach the segment from its virtual address space.
• The shmaddr argument identifies the segment to
be detached. It should be a value returned by a
previous call to shmat().
#include <sys/types.h> /* For portability */
#include <sys/shm.h>
int shmdt(const void *shmaddr);
Returns 0 on success, or –1 on error
• Detaching a shared memory segment is not the
same as deleting it. Deletion is performed using
the shmctl() IPC_RMID operation.
• A child created by fork() inherits its parent’s
attached shared memory segments. Thus,
shared memory provides an easy method of
IPC between parent and child.
• During an exec(), all attached shared memory
segments are detached. Shared memory
segments are also automatically detached on
process termination.
Example: Transferring Data via Shared
Memory
• This is an example application that uses System V
shared memory and semaphores.
• The application consists of two programs: the writer
and the reader.
• The writer reads blocks of data from standard input and
copies (“writes”) them into a shared memory segment.
• The reader copies (“reads”) blocks of data from the
shared memory segment to standard output.
• In effect, the programs treat the shared memory
somewhat like a pipe.
• The two programs employ a pair of System V
semaphores in a binary semaphore protocol
(the initSemAvailable(), initSemInUse(),
reserveSem(), and releaseSem() functions to
ensure that:
 Only one process accesses the shared
memory segment at a time; and
 The processes alternate in accessing the
segment (i.e., the writer writes some data,
then the reader reads the data, then the
writer writes again, and so on).
Following figure provides an overview of the
use of these two semaphores.
• Writer initializes the two semaphores so that it is the
first of the two programs to be able to access the
shared memory segment; that is, the writer’s
semaphore is initially available, and the reader’s
semaphore is initially in use.
• The source code for the application consists of three
files.
 The first of these, is a header file shared by the reader
and writer programs. This header defines the shmseg
structure that we use to declare pointers to the shared
memory segment.
 Second is the writer program
 Third is the reader program.
writer program performs the following
steps:
• Create a set containing the two semaphores that are used by the
writer and reader program to ensure that they alternate in
accessing the shared memory segment. The semaphores are
initialized so that the writer has first access to the shared memory
segment. Since the writer creates the semaphore set, it must be
started before the reader.
• Create the shared memory segment and attach it to the writer’s
virtual address space at an address chosen by the system.
• Enter a loop that transfers data from standard input to the shared
memory segment. The following steps are performed in each loop
iteration:
-- Reserve (decrement) the writer semaphore.
-- Read data from standard input into the shared memory segment.
-- Release (increment) the reader semaphore.
• The loop terminates when no further data is
available from standard input. On the last pass
through the loop, the writer indicates to the
reader that there is no more data by passing a
block of data of length 0 (shmp–>cnt is 0).
• Upon exiting the loop, the writer once more
reserves its semaphore, so that it knows that
the reader has completed the final access to
the shared memory. The writer then removes
the shared memory segment and semaphore
set.
The reader performs the following steps:
• Obtain the IDs of the semaphore set and shared memory segment
that were created by the writer program.
• Attach the shared memory segment for read-only access.
• Enter a loop that transfers data from the shared memory segment.
The following steps are performed in each loop iteration:
– Reserve (decrement) the reader semaphore.
– Check whether shmp–>cnt is 0; if so, exit this loop
– Write the block of data in the shared memory segment to standard
output
– Release (increment) the writer semaphore

• After exiting the loop, detach the shared memory segment and
releases the writer semaphore o, so that the writer program can
remove the IPC objects.
Header file for svshm_xfr_writer.c and svshm_xfr_reader.c
–––––––svshm/svshm_xfr.h
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include "tlpi_hdr.h"

#define SHM_KEY 0x1234 /* Key for shared memory segment */


#define SEM_KEY 0x5678 /* Key for semaphore set */

#define OBJ_PERMS (S_IRUSR | S_IWUSR | S_IRGRP |


S_IWGRP)
/* Permissions for our IPC objects */
#define WRITE_SEM 0 /* Writer has access to shared
memory */
#define READ_SEM 1 /* Reader has access to shared
memory */
#ifndef BUF_SIZE /* Allow "cc -D" to override definition */
#define BUF_SIZE 1024 /* Size of transfer buffer */
#endif

struct shmseg { /* Defines structure of shared memory


segment */
int cnt; /* Number of bytes used in 'buf' */
char buf[BUF_SIZE]; /* Data being transferred */
};
Header file for svshm_xfr_writer.c and
svshm_xfr_reader.c
–––––––semun.h
#ifndef SEMUN_H
#define SEMUN_H /* Prevent accidental double inclusion */
#include <sys/types.h> /* For portability */
#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
};
#endif
Transfer blocks of data from stdin to a System V shared
memory segment
–––––––––––– svshm/svshm_xfr_writer.c
#include "semun.h" /* Definition of semun union */
#include "svshm_xfr.h"

int bsUseSemUndo = 0;
int bsRetryOnEintr = 1;

int /* Initialize semaphore to 1 (i.e., "available") */


initSemAvailable(int semId, int semNum)
{
union semun arg;
arg.val = 1;
return semctl(semId, semNum, SETVAL, arg);
}
int /* Initialize semaphore to 0 (i.e., "in use") */
initSemInUse(int semId, int semNum)
{
union semun arg;
arg.val = 0;
return semctl(semId, semNum, SETVAL, arg);
}
/* Reserve semaphore (blocking), return 0 on success, or -1 with
'errno'
set to EINTR if operation was interrupted by a signal handler */
int /* Reserve semaphore - decrement it by 1 */
reserveSem(int semId, int semNum)
{
struct sembuf sops;
sops.sem_num = semNum;
sops.sem_op = -1;
sops.sem_flg = bsUseSemUndo ? SEM_UNDO : 0;
while (semop(semId, &sops, 1) == -1)
if (errno != EINTR || !bsRetryOnEintr)
return -1;
return 0;
}
int /* Release semaphore - increment it by 1 */
releaseSem(int semId, int semNum)
{
struct sembuf sops;
sops.sem_num = semNum;
sops.sem_op = 1;
sops.sem_flg = bsUseSemUndo ? SEM_UNDO : 0;
return semop(semId, &sops, 1);
}
Int main(int argc, char *argv[])
{
int semid, shmid, bytes, xfrs;
struct shmseg *shmp;
union semun dummy;
semid = semget(SEM_KEY, 2, IPC_CREAT | OBJ_PERMS);

if (semid == -1)
{
perror("semget");
exit(0);
}

if (initSemAvailable(semid, WRITE_SEM) == -1)


{
perror("initSemAvailable");
exit(0);
}
if (initSemInUse(semid, READ_SEM) == -1)
{
perror("initSemInUse");
exit(0);
}
shmid = shmget(SHM_KEY, sizeof(struct shmseg),
IPC_CREAT | OBJ_PERMS);
if (shmid == -1)
{
perror("shmget");
exit(0);
}
shmp = shmat(shmid, NULL, 0);
if (shmp == (void *) -1)
{
perror("shmat");
exit(0);
}
/* Transfer blocks of data from stdin to shared memory */
for (xfrs = 0, bytes = 0; ; xfrs++, bytes += shmp->cnt) {
if (reserveSem(semid, WRITE_SEM) == -1) /* Wait for our turn */
{
perror("reserveSem");
exit(0);
}
shmp->cnt = read(STDIN_FILENO, shmp->buf, BUF_SIZE);
if (shmp->cnt == -1)
{
perror("read");
exit(0);
if (releaseSem(semid, READ_SEM) == -1) /* Give
reader a turn */
{
perror("releaseSem");
exit(0);
}
/* Have we reached EOF? We test this after giving
the reader turn so that it can see the 0 value in
shmp->cnt. */
if (shmp->cnt == 0)
break;
}
/* Wait until reader has let us have one more turn. We then know reader has finished, and so we can delete the IPC
objects. */
if (reserveSem(semid, WRITE_SEM) == -1)
{
perror("reserveSem");
exit(0);
}
if (semctl(semid, 0, IPC_RMID, dummy) == -1)
{
perror("semctl");
exit(0);
}
if (shmdt(shmp) == -1)
{
perror("shmdt");
exit(0);
}
if (shmctl(shmid, IPC_RMID, 0) == -1)
{
perror("shmctl");
exit(0);
}
fprintf(stderr, "Sent %d bytes (%d xfrs)\n", bytes, xfrs);
exit(0);
}
Transfer blocks of data from a System V shared memory segment
to stdout
–––––––– svshm/svshm_xfr_reader.c
#include "svshm_xfr.h"
#include "semun.h“

int bsUseSemUndo = 0;
int bsRetryOnEintr = 1;

int /* Initialize semaphore to 1 (i.e., "available") */


initSemAvailable(int semId, int semNum)
{
union semun arg;
arg.val = 1;
return semctl(semId, semNum, SETVAL, arg);
}
int /* Initialize semaphore to 0 (i.e., "in use") */
initSemInUse(int semId, int semNum)
{
union semun arg;
arg.val = 0;
return semctl(semId, semNum, SETVAL, arg);
}
/* Reserve semaphore (blocking), return 0 on success, or -1 with 'errno'
set to EINTR if operation was interrupted by a signal handler */
int /* Reserve semaphore - decrement it by 1 */
reserveSem(int semId, int semNum)
{
struct sembuf sops;
sops.sem_num = semNum;
sops.sem_op = -1;
sops.sem_flg = bsUseSemUndo ? SEM_UNDO : 0;
while (semop(semId, &sops, 1) == -1)
if (errno != EINTR || !bsRetryOnEintr)
return -1;
return 0;
int /* Release semaphore - increment it by 1 */
releaseSem(int semId, int semNum)
{
struct sembuf sops;
sops.sem_num = semNum;
sops.sem_op = 1;
sops.sem_flg = bsUseSemUndo ? SEM_UNDO : 0;
return semop(semId, &sops, 1);
}
int
main(int argc, char *argv[])
{
int semid, shmid, xfrs, bytes;
struct shmseg *shmp;
/* Get IDs for semaphore set and shared memory created by writer */
semid = semget(SEM_KEY, 0, 0);
if (semid == -1)
{
perror("semget:");
exit(0);
}
shmid = shmget(SHM_KEY, 0, 0);
if (shmid == -1)
{
perror("shmget:");
exit(0);
}
shmp = shmat(shmid, NULL, SHM_RDONLY);
if (shmp == (void *) -1)
{
perror("shmat:");
exit(0);
}
/* Transfer blocks of data from shared memory to stdout */
for (xfrs = 0, bytes = 0; ; xfrs++) {
if (reserveSem(semid, READ_SEM) == -1) /* Wait for our turn */
{
perror("reserveSem");
exit(0);
}
if (shmp->cnt == 0) /* Writer encountered EOF */
break;
bytes += shmp->cnt;
if (write(STDOUT_FILENO, shmp->buf, shmp->cnt) != shmp->cnt)
{
printf("partial/failed write");
exit(0);
}
if (releaseSem(semid, WRITE_SEM) == -1) /* Give writer a turn */
{
perror("releaseSem");
exit(0);
}
}
if (shmdt(shmp) == -1)
{
perror("shmdt");
exit(0);
}
/* Give writer one more turn, so it can clean up */
if (releaseSem(semid, WRITE_SEM) == -1)
{
perror("releaseSem");
exit(0);
}
fprintf(stderr, "Received %d bytes (%d xfrs)\n", bytes, xfrs);
exit(0);
}
OutPut
• $ wc -c /etc/services Display size of test file
764360 /etc/services
• $ ./svshm_xfr_writer < /etc/services &
[1] 9403
• $ ./svshm_xfr_reader > out.txt
Received 764360 bytes (747 xfrs) Message from reader
Sent 764360 bytes (747 xfrs) Message from writer
[1]+ Done ./svshm_xfr_writer < /etc/services
• $ diff /etc/services out.txt
• $
Location of Shared Memory in Virtual
Memory
• If we follow the recommended approach of allowing the kernel to
choose where to attach a shared memory segment, then (on the
x86-32 architecture) the memory layout appears as shown in Figure
48-2, with the segment being attached in the unallocated space
between the upwardly growing heap and the downwardly growing
stack.
• To allow space for heap and stack growth, shared memory
segments are attached starting at the virtual address 0x40000000.
shared libraries are also placed in this area.
• The address 0x40000000 is defined as the kernel constant
TASK_UNMAPPED_BASE. It is possible to change this address by
defining this constant with a different value and rebuilding the
kernel.
• A shared memory segment (or memory mapping) can be placed at
an address below TASK_UNMAPPED_BASE, if we employ the
unrecommended approach of explicitly specifying an address when
calling shmat() (or mmap()).
Linux-specific /proc/PID/maps file
• Using the Linux-specific /proc/PID/maps file, we
can see the location of the shared memory
segments and shared libraries mapped by a
program, as we demonstrate in the shell session
below.
• Programs required for this are as follows.
svshm_create.c
 svshm_attach.c
 svshm_rm.c
svshm_create.c:
• This program creates a shared memory
segment. This program takes the same
command-line options as the corresponding
programs that we provide for message
queues and semaphores, but includes an
additional argument that specifies the size of
the segment.
svshm_create.c:
Program
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include "tlpi_hdr.h"

static void
usageError(const char *progName, const char *msg)
{
if (msg != NULL)
fprintf(stderr, "%s", msg);
fprintf(stderr, "Usage: %s [-cx] {-f pathname | -k key | -p} "
"seg-size [octal-perms]\n", progName);
fprintf(stderr, " -c Use IPC_CREAT flag\n");
fprintf(stderr, " -x Use IPC_EXCL flag\n");
fprintf(stderr, " -f pathname Generate key using ftok()\n");
fprintf(stderr, " -k key Use 'key' as key\n");
fprintf(stderr, " -p Use IPC_PRIVATE key\n");
exit(EXIT_FAILURE);
}
int
main(int argc, char *argv[])
{
int numKeyFlags; /* Counts -f, -k, and -p options */
int flags, shmid, segSize;
unsigned int perms;
long lkey;
key_t key;
int opt; /* Option character from getopt() */

/* Parse command-line options and arguments */

numKeyFlags = 0;
flags = 0;

while ((opt = getopt(argc, argv, "cf:k:px")) != -1) {


switch (opt) {
case 'c':
flags |= IPC_CREAT;
break;

case 'f': /* -f pathname */


key = ftok(optarg, 1);
if (key == -1)
{
perror("ftok");
exit(0);
}
numKeyFlags++;
break;

case 'k': /* -k key (octal, decimal or hexadecimal) */


if (sscanf(optarg, "%li", &lkey) != 1)
{
printf("-k option requires a numeric argument\n");
exit(0);
}
key = lkey;
numKeyFlags++;
break;

case 'p':
key = IPC_PRIVATE;
numKeyFlags++;
break;

case 'x':
flags |= IPC_EXCL;
break;

default:
usageError(argv[0], NULL);
}
}
if (numKeyFlags != 1)
usageError(argv[0], "Exactly one of the options -f, -k, "
"or -p must be supplied\n");

if (optind >= argc)


usageError(argv[0], "Size of segment must be specified\n");

segSize = atoi(argv[optind]);

perms = (S_IRUSR | S_IWUSR);

shmid = shmget(key, segSize, flags | perms);


if (shmid == -1)
{
perror("shmget");
exit(0);
}

printf("%d\n", shmid); /* On success, display shared mem. id */


exit(0);
svshm_attach.c Program
• This program attaches the shared memory segments
identified by its command-line arguments. Each of
these arguments is a colon-separated pair of numbers
consisting of a shared memory identifier and an attach
address. Specifying 0 for the attach address means
that the system should choose the address. The
program displays the address at which the memory is
actually attached. For informational purposes, the
program also displays the value of the SHMLBA
constant and the process ID of the process running the
program.
#include <sys/types.h>
#include <sys/shm.h>
#include "tlpi_hdr.h"
static void
usageError(char *progName)
{
fprintf(stderr, "Usage: %s [shmid:address[rR]]...\
n", progName);
fprintf(stderr, " r=SHM_RND;
R=SHM_RDONLY\n");
exit(EXIT_FAILURE);
}
int
main(int argc, char *argv[])
{
void *addr;
char *retAddr, *p;
int j, flags, shmid;

printf("SHMLBA = %ld (%#lx), PID = %ld\n",


(long) SHMLBA, (unsigned long) SHMLBA, (long) getpid());

for (j = 1; j < argc; j++) {


shmid = strtol(argv[j], &p, 0);
if (*p != ':')
usageError(argv[0]);
addr = (void *) strtol(p + 1, NULL, 0);
flags = (strchr(p + 1, 'r') != NULL) ? SHM_RND : 0;
if (strchr(p + 1, 'R') != NULL)
flags |= SHM_RDONLY;

retAddr = shmat(shmid, addr, flags);


if (retAddr == (void *) -1)
{
printf("shmat: %s", argv[j]);
exit(0);
}

printf("%d: %s ==> %p\n", j, argv[j], retAddr);


}

printf("Sleeping 5 seconds\n");
sleep(5);

exit(EXIT_SUCCESS);
}
svshm_rm.c Program
• The svshm_rm.c program deletes the shared memory segments identified by its command-line arguments.
#include <sys/types.h>
#include <sys/shm.h>
#include "tlpi_hdr.h"
int
main(int argc, char *argv[])
{
int j;

if (argc > 1 && strcmp(argv[1], "--help") == 0)


{
printf("%s [shmid...]\n", argv[0]);
exit(0);
}

for (j = 1; j < argc; j++)


if (shmctl(atoi(argv[j]), IPC_RMID, NULL) == -1)
{
printf("shmctl %s", argv[j]);
exit(0);
}

exit(EXIT_SUCCESS);
• We begin the shell session by creating two shared memory
segments (100 kB and 3200 kB in size):
• $ ./svshm_create -p 102400
9633796
• $ ./svshm_create -p 3276800
9666565
• $ ./svshm_attach 9633796:0 9666565:0
SHMLBA = 4096 (0x1000), PID = 9903
1: 9633796:0 ==> 0xb7f0d000
2: 9666565:0 ==> 0xb7bed000
Sleeping 5 seconds
Type Control-Z to suspend program
[1]+ Stopped ./svshm_attach 9633796:0 9666565:0
• $ cat /proc/9903/maps
• 1 08048000-0804a000 r-xp 00000000 08:05 5526989 /home/mtk/svshm_attach
• 0804a000-0804b000 r--p 00001000 08:05 5526989 /home/mtk/svshm_attach
• 0804b000-0804c000 rw-p 00002000 08:05 5526989 /home/mtk/svshm_attach
• 2 b7bed000-b7f0d000 rw-s 00000000 00:09 9666565 /SYSV00000000 (deleted)
• b7f0d000-b7f26000 rw-s 00000000 00:09 9633796 /SYSV00000000 (deleted)
• b7f26000-b7f27000 rw-p b7f26000 00:00 0
• 3 b7f27000-b8064000 r-xp 00000000 08:06 122031 /lib/libc-2.8.so
• b8064000-b8066000 r--p 0013d000 08:06 122031 /lib/libc-2.8.so
• b8066000-b8067000 rw-p 0013f000 08:06 122031 /lib/libc-2.8.so
• b8067000-b806b000 rw-p b8067000 00:00 0
• b8082000-b8083000 rw-p b8082000 00:00 0
• 4 b8083000-b809e000 r-xp 00000000 08:06 122125 /lib/ld-2.8.so
• b809e000-b809f000 r--p 0001a000 08:06 122125 /lib/ld-2.8.so
• b809f000-b80a0000 rw-p 0001b000 08:06 122125 /lib/ld-2.8.so
• 5 bfd8a000-bfda0000 rw-p bffea000 00:00 0 [stack]
• 6 ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso]
In the output from /proc/PID/maps shown in
above Listing , we can see the following:
• Three lines for the main program, shm_attach. These correspond to the
text and data segments of the program 1. The second of these lines is
for a readonly page holding the string constants used by the program.
• Two lines for the attached System V shared memory segments 2.
• Lines corresponding to the segments for two shared libraries. One of
these is the standard C library (libc-version.so) 3. The other is the
dynamic linker (ld-version.so), which we describe in Section 41.4.3 4
• A line labeled [stack]. This corresponds to the process stack 5.
• A line containing the tag [vdso] 6. This is an entry for the linux-gate
virtual dynamic shared object (DSO). This entry appears only in kernels
since 2.6.12. See http://www.trilithium.com/johan/2005/08/linux-gate/
for further information about this entry.
The following columns are shown in each line
of /proc/PID/maps, in order from left
to right:
• A pair of hyphen-separated numbers indicating the virtual address range (in
hexadecimal) at which the memory segment is mapped. The second of
these numbers is the address of the next byte after the end of the segment.
• Protection and flags for this memory segment. The first three letters indicate
the protection of the segment: read (r), write (w), and execute (x). A hyphen
(-) in place of any of these letters indicates that the corresponding
protection is disabled. The final letter indicates the mapping flag for the
memory segment; it is either private (p) or shared (s). For an explanation of
these flags, see the description of the MAP_PRIVATE and MAP_SHARED
flags in Section 49.2. (A System V shared memory segment is always marked
shared.)
• The hexadecimal offset (in bytes) of the segment within the corresponding
mapped file. The meanings of this and the following two columns will
become clearer when we describe the mmap() system call in Chapter 49. For
a System V shared memory segment, the offset is always 0.
• The device number (major and minor IDs) of the device
on which the corresponding mapped file is located.
• The i-node number of the mapped file, or, for System V
shared memory segments, the identifier for the segment.
• The filename or other identifying tag associated with this
memory segment. For a System V shared memory
segment, this consists of the string SYSV concatenated
with the shmget() key of the segment (expressed in
hexadecimal). In this example, SYSV is followed by zeros
because we created the segments using the key
IPC_PRIVATE (which has the value 0). The string (deleted)
that appears after the SYSV field for a System V shared
memory segment is an artifact of the implementation of
shared memory segments.
Shared Memory Associated Data Structure
Each shared memory segment has an associated shmid_ds data structure of
the following
form:
struct shmid_ds {
struct ipc_perm shm_perm; /* Ownership and permissions */
size_t shm_segsz; /* Size of segment in bytes */
time_t shm_atime; /* Time of last shmat() */
time_t shm_dtime; /* Time of last shmdt() */
time_t shm_ctime; /* Time of last change */
pid_t shm_cpid; /* PID of creator */
pid_t shm_lpid; /* PID of last shmat() / shmdt() */
shmatt_t shm_nattch; /* Number of currently attached processes */
};
Shared Memory Limits
• SHMMNI
This is a system-wide limit on the number of shared memory identifiers (in other
words, shared memory segments) that can be created. (shmget(), ENOSPC)
• SHMMIN
This is the minimum size (in bytes) of a shared memory segment. This limit is
defined with the value 1 (this can’t be changed). However, the effective limit is
the system page size. (shmget(), EINVAL)
• SHMMAX
This is the maximum size (in bytes) of a shared memory segment. The practical
upper limit for SHMMAX depends on available RAM and swap space. (shmget(),
EINVAL)
• SHMALL
This is a system-wide limit on the total number of pages of shared memory.
Most other UNIX implementations don’t provide this limit. The practical upper
limit for SHMALL depends on available RAM and swap space. (shmget(),
ENOSPC)
• SHMSEG
• $ cd /proc/sys/kernel
• $ cat shmmni
4096
• $ cat shmmax
33554432
• $ cat shmall
2097152
Shared Memory Control Operations
• The shmctl() system call performs a range of
control operations on the shared memory
segment identified by shmid.
#include <sys/types.h> /* For portability */
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds
*buf);
Returns 0 on success, or –1 on error
• The cmd argument specifies the control operation to be performed.
The buf argument is required by the IPC_STAT and IPC_SET
operations (described below), and should be specified as NULL for
the remaining operations.
• IPC_RMID
Mark the shared memory segment and its associated shmid_ds
data structure for deletion. If no processes currently have the
segment attached, deletion is immediate; otherwise, the segment is
removed after all processes have detached from it (i.e., when the
value of the shm_nattch field in the shmid_ds data structure falls to
0).
• IPC_STAT
Place a copy of the shmid_ds data structure associated with this
shared memory segment in the buffer pointed to by buf.
• IPC_SET
Update selected fields of the shmid_ds data structure associated
with this shared memory segment using values in the buffer pointed
Locking and unlocking shared memory
A shared memory segment can be locked into RAM, so that
it is never swapped out. This provides a performance
benefit, since, once each page of the segment is
memory-resident, an application is guaranteed never to
be delayed by a page fault when it accesses the page.
There are two shmctl() locking operations:
• The SHM_LOCK operation locks a shared memory
segment into memory.
• The SHM_UNLOCK operation unlocks the shared
memory segment, allowing it to be swapped out.

You might also like