Creating a Shared Memory Segment
The shmget system call is used to create the shared memory segment and generate the associated system data structure or to gain access to an existing segment. The shared memory segment and the system data structure are identified by a unique shared memory identifier that the shmget system call returns (see Table 8.1).
Providing no system parameters are exceeded, the shmget system call creates a new shared memory segment if
- The value for its first argument, key , is the symbolic constant IPC_PRIVATE, or
- the value key is not associated with an existing shared memory identifier and the IPC_CREAT flag is set as part of the shmflg argument ( otherwise , the existing shared memory identifier associated with the key value is returned), or
Table 8.1. Summary of the shmget System Call.
Include File(s)
Manual Section
2
Summary
int shmget(key_t key, int size ,int shmflg);
Return
Success
Failure
Sets errno
Shared memory identifier.
-1
Yes
- the value key is not associated with an existing shared memory identifier and the IPC_CREAT along with the IPC_EXCL flag have been set as part of the shmflg argument. With IPC_CREAT and IPC_EXCL set, the user can be assured of creating a unique shared memory segment without inadvertently gaining access to a preexisting segment.
As with previous IPC system calls for message queues and semaphores, the ftok library function can be used to generate a key value.
The argument size determines the size in bytes of the shared memory segment. If we are using shmget to access an existing shared memory segment, size can be set to 0, as the segment size is set by the creating process. Common overall default system maximums, as related to shared memory, are shown in Table 8.2.
Table 8.2. Shared Memory Limits.
Shared Memory Segment Defaults |
Constant |
Value |
---|---|---|
Maximum segment size |
SHMMAX |
4 MB |
Minimum segment size |
SHMMIN |
1 byte |
Systemwide maximum number of segments |
SHMMNI |
4096 |
Maximum number of segments per process |
SHMSEG |
Not specified |
The last argument for shmget , shmflg , is used to indicate segment creation conditions (e.g., IPC_CREAT, IPC_EXCL) and access permissions (stored in the low order 9 bits of shmflg ). At this time the system does not use the execute permission settings. To specify creation conditions along with access permissions, the individual items are bitwise OR ed (e.g., 0660 IPC_CREAT).
The shmget system call does not entitle the creating process to actually use the allocated memory; it merely reserves the requested memory. To be used by the process, the allocated memory must be attached to the process using a separate system call. The technique for accomplishing this is discussed in Section 8.4.
If shmget is successful in allocating a shared memory segment, it returns an integer shared memory identifier. At creation time, the system data structure shmid_ds , defined in the header file, is generated and initialized . As with other System V IPC facilities, the user does not directly include but instead includes the standard header file for shared memory , which in turn includes the . The standard definition for the shmid_ds data structure follows :
struct shmid_ds { struct ipc_perm shm_perm; /* operation permission struct */ size_t shm_segsz; /* size of segment in bytes */ __time_t shm_atime; /* time of last shmat() */ unsigned long int __unused1; __time_t shm_dtime; /* time of last shmdt() */ unsigned long int __unused2; __time_t shm_ctime; /* time of last change by shmctl() */ unsigned long int __unused3; __pid_t shm_cpid; /* pid of creator */ __pid_t shm_lpid; /* pid of last shmop */ shmatt_t shm_nattch; /* number of current attaches */ unsigned long int __unused4; unsigned long int __unused5; };
The source files for the kernel for System V IPC (found in /usr/src/ linux-XX.XX.XX/ipc where XX are the version numbers of the operating system) defines a similar private kernel shared memory structure called shmid_kernel .
The shmid_ds structure contains an ipc_perm permission structure called shm_perm . When created, the shm_perm.cuid and shm_perm.uid members are assigned the effective user ID of the calling process, and the shm_perm.cgid and shm_perm.gid members are set to the group ID of the calling process. The access permission bits, stored in the shm_perm.mode member, are set according to the value specified by the shmflg value. The shm_segsz member is set to the specified size from the shmget system call. The shm_lpid , shm_nattch , shm_atime , and shm_dtime members are each set to 0, while the shm_ctime member is set to the current time. The shm_cpid member stores the ID of the creating process.
If shmget fails, it returns a value of -1 and sets the value in errno to indicate the specific error condition. The values that errno may be assigned and their interpretations are shown in Table 8.3.
Table 8.3. shmget Error Messages
# |
Constant |
perror Message |
Explanation |
---|---|---|---|
2 |
EOENT |
No such file or directory |
The shared memory identifier does not exist for this key , and IPC_CREAT was not set. |
12 |
ENOMEM |
Cannot allocate memory |
When creating a shared memory segment, insufficient memory is available. |
13 |
EACCES |
Permission denied |
The shared memory identifier exists for this key , but the requested operation is not allowed by the current access permissions. |
17 |
EEXIST |
File exists |
Shared memory identifier exists for this key , but IPC_CREAT and IPC_EXCL are both set. |
22 |
EINVAL |
Invalid argument |
|
28 |
ENOSPC |
No space left on device |
System-imposed limit for number of shared memory segments has been reached. |
43 |
EIDRM |
Identifier removed |
Memory segment is marked as removed. |
Program 8.1 attempts to create two shared memory segments of differing sizes.
Program 8.1 Creating shared memory segments.
File : p8.1.cxx /* Allocating a shared memory segment */ #include + #include #include #include using namespace std; int 10 main( ) { key_t key = 15; int shmid_1, shmid_2; if ((shmid_1=shmget(key, 1000, 0640IPC_CREAT)) == -1){ perror("shmget shmid_1"); + return 1; } cout << "First shared memory identifier is : " << shmid_1 << endl; if ((shmid_2=shmget(IPC_PRIVATE, 20, 0640)) == -1){ perror("shmget shmid_2"); 20 return 2; } cout << "Second shared memory identifier is: " << shmid_2 << endl; return 0; }
Figure 8.2 shows the output of Program 8.1 when invoked twice in succession.
Figure 8.2 Output of Program 8.1.
linux$ p8.1 <-- 1 First shared memory identifier is : 40665091 Second shared memory identifier is: 40697860 linux$ ipcs -m <-- 2 ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x0000000f 40665091 gray 640 1000 0 0x00000000 40697860 gray 640 20 0 linux$ p8.1 <-- 3 First shared memory identifier is : 40665091 Second shared memory identifier is: 40730629 linux$ ipcs -m <-- 4 ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x0000000f 40665091 gray 640 1000 0 0x00000000 40697860 gray 640 20 0 0x00000000 40730629 gray 640 20 0
(1) Run the program.
(2) Check with ipcs .
(3) Run the program again.
(4) Recheck with ipcs .
Examination of the output shows the first invocation created two shared memory segments with the identifier values of 40665091 and 40697860 . The first segment, with the shared memory identification value of 40665091 , was created by the first call to shmget , as the key value (15) coded in the program was not associated with any other previously allocated memory segment. The second segment, identified by the 40697860 , was created by shmget , since IPC_PRIVATE was specified. However, when the program was invoked the second time, the results were slightly different. The first call to shmget returned the shared memory identifier from the first invocation of the program, as the shared memory segment already existed for the key value of 15. The second call to shmget , since it uses IPC_PRIVATE, produced another unique shared memory segment (40730629) . Notice that the output for the ipcs command shows that the key value entries for both of the unique shared memory segments generated with IPC_PRIVATE are set to zero.