Shared Memory Operations
There are two shared memory operation system calls. The first, shmat , is used to attach (map) the referenced shared memory segment into the calling process's data segment. See Table 8.6.
Table 8.6. Summary of the shmat System Call.
Include File(s) |
|
Manual Section |
2 |
|
Summary |
void *shmat(int shmid, const void *shmaddr, int shmflg); |
|||
Return |
Success |
Failure |
Sets errno |
|
Reference to the data segment |
-1 |
Yes |
The first argument to shmat , shmid , is a valid shared memory identifier. The second argument, shmaddr , allows the calling process some flexibility in assigning the location of the shared memory segment. If a nonzero value is given, shmat uses this as the attachment address for the shared memory segment. If shmaddr is 0, the system picks the attachment address. In most situations ( especially if portability is of concern), it is advisable to use a value of 0 and have the system pick the address. The third argument, shmflg , is used to specify the access permissions for the shared memory segment and to request special attachment conditions, such as an aligned address or a read-only segment. The values of shmaddr and shmflg are used by the system to determine the attachment address, using the algorithm shown in Figure 8.3.
Figure 8.3. Determining the attachment address.
By default, attached segments are accessible for reading and writing. If needed, the SHM_RDONLY flag can be bitwise OR ed with the shmflg value to indicate a read-only segment. There is no flag to specify a write-only memory segment. The SHM_RND flag is used to specify whether or not the attachment address should be aligned on a page boundary. The value in the defined constant SHMLBA (found in ) is used by the system as the page size . For reference, a page is a unit of virtual address space. When a page is mapped to physical memory it is called a page frame.
When shmat is successful, it returns the address of the actual attachment. It also sets shm_atime to the current time, shm_lpid to the ID of the calling process, and increments shm_nattch by one. If shmat fails, it returns a value of -1 and sets errno to indicate the source of the error. Table 8.7 lists the error codes generated and their interpretation when the shmat system call fails. Remember that after a fork , the child inherits the attached shared memory segment(s). However, after an exec or an exit attached, shared memory segment(s) are detached but are not destroyed .
Table 8.7. shmat Error Messages.
# |
Constant |
perror Message |
Explanation |
---|---|---|---|
12 |
ENOMEM |
Cannot allocate memory |
There is insufficient memory available to accommodate the shared memory segment. |
13 |
EACCES |
Permission denied |
The requested operation is not allowed by current access permissions. |
22 |
EINVAL |
Invalid argument |
|
24 |
EMFILE |
Too many open files |
Number of attached memory segments has exceeded system limits. |
The second shared memory operation, shmdt , is used to detach the calling process's data segment from the shared memory segment. See Table 8.8.
Table 8.8. Summary of the shmdt System Call
Include File(s) |
|
Manual Section |
2 |
|
Summary |
int shmdt ( const void *shmaddr); |
|||
Return |
Success |
Failure |
Sets errno |
|
-1 |
Yes |
The shmdt system call has one argument, shmaddr , which is a reference to an attached memory segment. If shmdt is successful in detaching the memory segment, it returns a value of 0. It also sets shm_atime to the current time, shm_lpid to the ID of the calling process, and decrements shm_nattch by one. If shm_nattch becomes 0 and the memory segment is marked for deletion by the operating system, it is removed. If the shmdt call fails, it returns a value of -1 and sets errno . Table 8.9 gives the error code that is generated when shmdt fails.
Table 8.9. shmdt Error Message
# |
Constant |
perror Message |
Explanation |
---|---|---|---|
22 |
EINVAL |
Invalid argument |
The value in shmaddr does not reference a valid shared memory segment. |
In Program 8.2, a private shared memory segment, 30 bytes in length, is created at line 18. The shared memory segment is mapped to the process's data space (line 22) using the first available address (as picked by the system). The actual attachment address along with the addresses for etext, edata , and end are displayed for reference. A character pointer is set to reference the shared memory segment, and then a sequence of uppercase alphabetic characters is written to the referenced location (lines 3133). A fork system call is used to generate a child process. The child process redisplays the contents of the shared memory segment. The child process then modifies the contents of the shared memory by converting the uppercase alphabetics to lowercase (line 49). After it converts the alphabetics, the child process detaches the shared memory segment and exits. The parent process, after waiting for the child to exit, redisplays the contents of shared memory (which now is in lowercase), detaches the shared memory segment, and removes it.
Program 8.2 Creating, attaching, and manipulating shared memory.
File : p8.2.cxx /* Using shared memory */ #include + #include #include #include #include #include 10 #include #define SHM_SIZE 30 using namespace std; extern int etext, edata, end; int + main( ) { int shmid; char c, *shm, *s; if ((shmid=shmget(IPC_PRIVATE,SHM_SIZE,IPC_CREAT0660))< 0) { perror("shmget fail"); 20 return 1; } if ((shm = (char *)shmat(shmid, 0, 0)) == (char *) -1) { perror("shmat : parent"); return 2; + } cout << "Addresses in parent" << endl; cout << "shared mem: " << hex << int(shm) << " etext: " << &etext << " edata: " << &edata << " end: " << &end << endl << endl; 30 s = shm; // s now references shared mem for (c='A'; c <= 'Z'; ++c) // put some info there *s++ = c; *s='
File : p8.2.cxx /* Using shared memory */ #include < iostream > + #include #include #include #include #include 10 #include #define SHM_SIZE 30 using namespace std; extern int etext, edata, end; int + main( ) { int shmid; char c, *shm, *s; if ((shmid=shmget(IPC_PRIVATE,SHM_SIZE,IPC_CREAT0660))< 0) { perror(" shmget fail"); 20 return 1; } if ((shm = (char *)shmat(shmid, 0, 0)) == (char *) -1) { perror("shmat : parent"); return 2; + } cout << "Addresses in parent" << endl; cout << "shared mem: " << hex << int(shm) << " etext: " << &etext << " edata: " << &edata << " end: " << &end << endl << endl; 30 s = shm; // s now references shared mem for (c='A'; c <= 'Z'; ++c) // put some info there *s++ = c; *s='