NAME

semop — XSI semaphore operations

SYNOPSIS

[XSI] [Option Start] #include <sys/sem.h>

int semop(int
semid, struct sembuf *sops, size_t nsops); [Option End]

DESCRIPTION

The semop() function operates on XSI semaphores (see XBD 4.20 Semaphore ). It is unspecified whether this function interoperates with the realtime interprocess communication facilities defined in 2.8 Realtime .

The semop() function shall perform atomically a user-defined array of semaphore operations in array order on the set of semaphores associated with the semaphore identifier specified by the argument semid.

The argument sops is a pointer to a user-defined array of semaphore operation structures. The implementation shall not modify elements of this array unless the application uses implementation-defined extensions.

The argument nsops is the number of such structures in the array.

Each structure, sembuf, includes the following members:

Member Type

Member Name

Description

unsigned short

sem_num

Semaphore number.

short

sem_op

Semaphore operation.

short

sem_flg

Operation flags.

Each semaphore operation specified by sem_op is performed on the corresponding semaphore specified by semid and sem_num.

If all of the semaphore operations complete successfully, semop() shall return 0. If a semaphore operation fails or blocks, all changes to semadj and semval values performed by completed semaphore operations in the array before the operation that failed or blocked shall be undone before semop() returns or blocks, respectively. When a semaphore operation blocks, the change to semncnt or semzcnt indicating which semaphore operation blocked shall not be undone until the operation unblocks.

For each operation in the array of semaphore operations, the variable sem_op specifies one of three semaphore operations:

  1. If sem_op is a negative integer and the calling process has alter permission, one of the following shall occur:
    • If semval (see <sys/sem.h>) is greater than or equal to the absolute value of sem_op, the absolute value of sem_op shall be subtracted from semval. Also, if (sem_flg & SEM_UNDO) is non-zero, the absolute value of sem_op shall be added to the semadj value of the calling process for the specified semaphore. If this is not the last operation in the array of semaphore operations to be performed, processing shall continue with the next operation in the array.
    • If semval is less than the absolute value of sem_op and (sem_flg & IPC_NOWAIT) is non-zero, the operation shall fail with errno set to [EAGAIN].
    • If semval is less than the absolute value of sem_op and (sem_flg & IPC_NOWAIT) is 0, semop() shall increment the semncnt associated with the specified semaphore and suspend execution of the calling thread (block) until one of the following conditions occurs:
      • The value of semval changes. When this occurs, the value of semncnt associated with the specified semaphore shall be decremented and the array of semaphore operations shall be reevaluated.
      • The semid for which the calling thread is awaiting action is removed from the system. When this occurs, the operation shall fail with errno set to [EIDRM].
      • The calling thread receives a signal that is to be caught. When this occurs, the value of semncnt associated with the specified semaphore shall be decremented, and the calling thread shall resume execution in the manner prescribed in sigaction .
  2. If sem_op is a positive integer and the calling process has alter permission, the value of sem_op shall be added to semval and, if (sem_flg & SEM_UNDO) is non-zero, the value of sem_op shall be subtracted from the semadj value of the calling process for the specified semaphore. If this is not the last operation in the array of semaphore operations to be performed, processing shall continue with the next operation in the array.
  3. If sem_op is 0 and the calling process has read permission, one of the following shall occur:
    • If semval is 0, this is a successful operation. If this is not the last operation in the array of semaphore operations to be performed, processing shall continue with the next operation in the array.
    • If semval is non-zero and (sem_flg & IPC_NOWAIT) is non-zero, the operation shall fail with errno set to [EAGAIN].
    • If semval is non-zero and (sem_flg & IPC_NOWAIT) is 0, semop() shall increment the semzcnt associated with the specified semaphore and suspend execution of the calling thread (block) until one of the following occurs:
      • The value of semval changes. When this occurs, the value of semzcnt associated with the specified semaphore shall be decremented and the array of semaphore operations shall be reevaluated.
      • The semid for which the calling thread is awaiting action is removed from the system. When this occurs, the operation shall fail with errno set to [EIDRM].
      • The calling thread receives a signal that is to be caught. When this occurs, the value of semzcnt associated with the specified semaphore shall be decremented, and the calling thread shall resume execution in the manner prescribed in sigaction .

Upon successful completion of all of the semaphore operations specified in the array pointed to by sops, the value of sempid for each semaphore specified in the array shall be set to the process ID of the calling process and the sem_otime timestamp associated with the semaphore set shall be set to the current time, as described in 2.7.1 IPC General Description .

RETURN VALUE

Upon successful completion, semop() shall return 0; otherwise, it shall return -1 and set errno to indicate the error.

ERRORS

The semop() function shall fail if:

[E2BIG]
The value of nsops is greater than the system-imposed maximum.
[EACCES]
Operation permission is denied to the calling process; see 2.7 XSI Interprocess Communication .
[EAGAIN]
The operation would result in suspension of the calling thread but (sem_flg & IPC_NOWAIT) is non-zero.
[EFBIG]
The value of sem_num is greater than or equal to the number of semaphores in the set associated with semid.
[EIDRM]
The semaphore identifier semid is removed from the system.
[EINTR]
The semop() function was interrupted by a signal.
[EINVAL]
The value of semid is not a valid semaphore identifier, or the number of individual semaphores for which the calling process requests a SEM_UNDO would exceed the system-imposed limit.
[ENOSPC]
The limit on the number of individual processes requesting a SEM_UNDO would be exceeded.
[ERANGE]
An operation would cause a semval to overflow the system-imposed limit, or an operation would cause a semadj value to overflow the system-imposed limit.

The following sections are informative.

EXAMPLES

Setting Values in Semaphores

The following example sets the values of the two semaphores associated with the semid identifier to the values contained in the sb array.

#include <sys/sem.h>
...
int semid;
struct sembuf sb[2];
int nsops = 2;
int result;

// Code to initialize semid. ...
// Adjust value of semaphore in the semaphore array semid. sb[0].sem_num = 0; sb[0].sem_op = -1; sb[0].sem_flg = SEM_UNDO | IPC_NOWAIT; sb[1].sem_num = 1; sb[1].sem_op = 1; sb[1].sem_flg = 0;
result = semop(semid, sb, nsops);
Creating a Semaphore Identifier

The following example gets a semaphore key using the ftok() function, then creates or uses an existing semaphore set associated with that key using the semget() function.

If this process creates the semaphore set, the program uses a call to semop() to initialize it to the value in the sbuf array. The number of processes that can execute concurrently is set to 2.

The final call to semop() acquires the semaphore and waits until it is free; the SEM_UNDO option releases the semaphore when the process exits, waiting until there are less than two processes running concurrently.

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/sem.h>
#include <sys/stat.h>
...
struct sembuf sbuf;
int semid;
key_t semkey;
...
// Get a key for the semaphore set.
if ((semkey = ftok("/tmp", 'a')) == (key_t) -1) {
    perror("IPC error: ftok");
    exit(1);
}

// Create the semaphore set associated with this key if ((semid = semget(semkey, 1, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) != -1) { // Initialize the semaphore. sbuf.sem_num = 0; sbuf.sem_op = 2; // Set the number of runs without queuing. sbuf.sem_flg = 0; if (semop(semid, &sbuf, 1) == -1) { perror("IPC error: semop"); exit(1); } } else if (errno == EEXIST) { // The semaphore set already exists; get its semaphore ID. if ((semid = semget(semkey, 0, 0)) == -1) { perror("IPC error 1: semget"); exit(1); } } else { perror("IPC error 2: semget"); exit(1); } // Since the semget() initialized the semaphore to 0, the // following semop() will block until the creating process // completes the initialization above. Processes will also // block in the following semop() call if two other processes // have already passed this point and are still running. sbuf.sem_num = 0; sbuf.sem_op = -1; sbuf.sem_flg = SEM_UNDO; if (semop(semid, &sbuf, 1) == -1) { perror("IPC Error: semop"); exit(1); }

APPLICATION USAGE

The POSIX Realtime Extension defines alternative interfaces for interprocess communication. Application developers who need to use IPC should design their applications so that modules using the IPC routines described in 2.7 XSI Interprocess Communication can be easily modified to use the alternative interfaces.

RATIONALE

None.

FUTURE DIRECTIONS

None.

SEE ALSO

2.7 XSI Interprocess Communication , 2.8 Realtime , exec , exit , fork , semctl , semget , sem_close , sem_destroy , sem_getvalue , sem_init , sem_open , sem_post , sem_trywait , sem_unlink

XBD 4.20 Semaphore , <sys/ipc.h> , <sys/sem.h> , <sys/types.h>

CHANGE HISTORY

First released in Issue 2. Derived from Issue 2 of the SVID.

Issue 5

The note about use of POSIX Realtime Extension IPC routines has been moved from FUTURE DIRECTIONS to a new APPLICATION USAGE section.

Issue 7

SD5-XSH-ERN-171 is applied, updating the DESCRIPTION to clarify the order in which the operations in sops will be performed when there are multiple operations.

POSIX.1-2008, Technical Corrigendum 1, XSH/TC1-2008/0538 [329,429], XSH/TC1-2008/0539 [345,428], XSH/TC1-2008/0540 [329,429], XSH/TC1-2008/0541 [335], and XSH/TC1-2008/0542 [291,429] are applied.

Issue 8

Austin Group Defect 377 is applied, changing the EXAMPLES section.

Austin Group Defect 628 is applied, clarifying how semop() behaves when there is more than one operation in the array specified by sops.

End of informative text.