Semaphore Operations
semop(2) performs operations on a semaphore set. The semid argument is the semaphore ID returned by a previous semget(2) call. The sops argument is a pointer to an array of structures, each containing the following information about a semaphore operation:
The semaphore number
The operation to be performed
Control flags, if any
The sembuf structure specifies a semaphore operation, as defined in sys/sem.h. The nsops argument specifies the length of the array, the maximum size of which is determined by the SEMOPM configuration option. This option determines the maximum number of operations allowed by a single semop(2) call, and is set to 10 by default.
The operation to be performed is determined as follows:
Positive integer increments the semaphore value by that amount.
Negative integer decrements the semaphore value by that amount. An attempt to set a semaphore to a value less than zero fails or blocks, depending on whether IPC_NOWAIT is in effect.
Value of zero means to wait for the semaphore value to reach zero.
The two control flags that can be used with semop(2) are IPC_NOWAIT and SEM_UNDO.
IPC_NOWAIT | Can be set for any operations in the array. Makes the interface return without changing any semaphore value if it cannot perform any of the operations for which IPC_NOWAIT is set. The interface fails if it tries to decrement a semaphore more than its current value, or tests a nonzero semaphore to be equal to zero. |
SEM_UNDO | Allows individual operations in the array to be undone when the process exits. |
The following code illustrates semop(2).
#include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> ... int i; /* work area */ int nsops; /* number of operations to do */ int semid; /* semid of semaphore set */ struct sembuf *sops; /* ptr to operations to perform */ ... if ((i = semop(semid, sops, nsops)) == -1) { perror("semop: semop failed"); } else (void) fprintf(stderr, "semop: returned %d\n", i); ... |
System V Shared Memory
In the SunOS 5.9 operating system, the most efficient way to implement shared memory applications is to rely on mmap(2) and on the system's native virtual memory facility. See Chapter 1, Memory Management for more information.
The SunOS 5.9 platform also supports System V shared memory, which is a less efficient way to enable the attachment of a segment of physical memory to the virtual address spaces of multiple processes. When write access is allowed for more than one process, an outside protocol or mechanism, such as a semaphore, can be used to prevent inconsistencies and collisions.
A process creates a shared memory segment using shmget(2). This call is also used to get the ID of an existing shared segment. The creating process sets the permissions and the size in bytes for the segment.
The original owner of a shared memory segment can assign ownership to another user with shmctl(2). The owner can also revoke this assignment. Other processes with proper permission can perform various control functions on the shared memory segment using shmctl(2).
Once created, you can attach a shared segment to a process address space using shmat(2). You can detach it using shmdt(2). The attaching process must have the appropriate permissions for shmat(2). Once attached, the process can read or write to the segment, as allowed by the permission requested in the attach operation. A shared segment can be attached multiple times by the same process.
A shared memory segment is described by a control structure with a unique ID that points to an area of physical memory. The identifier of the segment is called the shmid. The structure definition for the shared memory segment control structure can be found in sys/shm.h.
Accessing a Shared Memory Segment
shmget(2) is used to obtain access to a shared memory segment. When the call succeeds, it returns the shared memory segment ID (shmid). The following code illustrates shmget(2).
#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> ... key_t key; /* key to be passed to shmget() */ int shmflg; /* shmflg to be passed to shmget() */ int shmid; /* return value from shmget() */ size_t size; /* size to be passed to shmget() */ ... key = ... size = ... shmflg) = ... if ((shmid = shmget (key, size, shmflg)) == -1) { perror("shmget: shmget failed"); exit(1); } else { (void) fprintf(stderr, "shmget: shmget returned %d\n", shmid); exit(0); } ... |
Controlling a Shared Memory Segment
shmctl(2) is used to alter the permissions and other characteristics of a shared memory segment. The cmd argument is one of following control commands.
SHM_LOCK | Lock the specified shared memory segment in memory. The process must have the effective ID of superuser to perform this command. |
SHM_UNLOCK | Unlock the shared memory segment. The process must have the effective ID of superuser to perform this command. |
IPC_STAT | Return the status information contained in the control structure and place it in the buffer pointed to by buf. The process must have read permission on the segment to perform this command. |
IPC_SET | Set the effective user and group identification and access permissions. The process must have an effective ID of owner, creator or superuser to perform this command. |
IPC_RMID | Remove the shared memory segment. The process must have an effective ID of owner, creator, or superuser to perform this command. |
The following code illustrates shmctl(2).
#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> ... int cmd; /* command code for shmctl() */ int shmid; /* segment ID */ struct shmid_ds shmid_ds; /* shared memory data structure to hold results */ ... shmid = ... cmd = ... if ((rtrn = shmctl(shmid, cmd, shmid_ds)) == -1) { perror("shmctl: shmctl failed"); exit(1); ... |