Semaphores let processes query or alter status information. They are often used to monitor and control the availability of system resources such as shared memory segments. semaphore set must be initialized using semget(); the semaphore creator can change its ownership or permissions using semctl(); and semaphore operations are performed via the semop() function. These are now discussed below:
INTIALISING A SEMAPHORE:
The function semget() initializes or gains access to a semaphore. It is prototyped by:
int semget(key_t key, int nsems, int semflg);
When the call succeeds, it returns the semaphore ID (semid).
The key argument is a access value associated with the semaphore ID.
The nsems argument specifies the number of elements in a semaphore array. The call fails when nsems is greater than the number of elements in an existing array; when the correct count is not known, supplying 0 for this argument ensures that it will succeed.
The semflg argument specifies the initial access permissions and creation control flags.
CONTROLLING A SEMAPHORE:
semctl() changes permissions and other characteristics of a semaphore set. It is prototyped as follows:
int semctl(int semid, int semnum, int cmd, union semun arg);
It must be called with a valid semaphore ID, semid. The semnum value selects a semaphore within an array by its index.The fourth argument union semun arg is optional, depending upon the operation requested.
SEMAPHORE OPERATION:
semop() performs operations on a semaphore set. It is prototyped by:
int semop(int semid, struct sembuf *sops, size_t nsops);
The semid argument is the semaphore ID returned by a previous semget() 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>.
struct sembuf { ushort_t sem_num; /* semaphore number */ short sem_op; /* semaphore operation */ short sem_flg; /* operation flags */ };
The nsops argument specifies the length of the array, the maximum size of which is determined by the SEMOPM configuration option; this is the maximum number of operations allowed by a single semop() call, and is set to 10 by default. The operation to be performed is determined as follows:
- A positive integer increments the semaphore value by that amount.
- A 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.
- A value of zero means to wait for the semaphore value to reach zero.
There are two control flags that can be used with semop():
- IPC_NOWAIT
- – Can be set for any operations in the array. Makes the function return without changing any semaphore value if any operation for which IPC_NOWAIT is set cannot be performed. The function 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.
This function takes a pointer, sops, to an array of semaphore operation structures. Each structure in the array contains data about an operation to perform on a semaphore. Any process with read permission can test whether a semaphore has a zero value. To increment or decrement a semaphore requires write permission. When an operation fails, none of the semaphores is altered.
The process blocks (unless the IPC_NOWAIT flag is set), and remains blocked until:
- the semaphore operations can all finish, so the call succeeds,
- the process receives a signal, or
- the semaphore set is removed.
Only one process at a time can update a semaphore. Simultaneous requests by different processes are performed in an arbitrary order. When an array of operations is given by a semop() call, no updates are done until all operations on the array can finish successfully.
If a process with exclusive use of a semaphore terminates abnormally and fails to undo the operation or free the semaphore, the semaphore stays locked in memory in the state the process left it. To prevent this, the SEM_UNDO control flag makes semop() allocate an undo structure for each semaphore operation, which contains the operation that returns the semaphore to its previous state. If the process dies, the system applies the operations in the undo structures. This prevents an aborted process from leaving a semaphore set in an inconsistent state. If processes share access to a resource controlled by a semaphore, operations on the semaphore should not be made with SEM_UNDO in effect. If the process that currently has control of the resource terminates abnormally, the resource is presumed to be inconsistent. Another process must be able to recognize this to restore the resource to a consistent state. When performing a semaphore operation with SEM_UNDO in effect, you must also have it in effect for the call that will perform the reversing operation. When the process runs normally, the reversing operation updates the undo structure with a complementary value. This ensures that, unless the process is aborted, the values applied to the undo structure are cancel to zero. When the undo structure reaches zero, it is removed.