# semop

## PROLOG



           This manual page is part of the POSIX Programmer's Manual.  The
           Linux implementation of this interface may differ (consult the
           corresponding Linux manual page for details of Linux behavior), or
           the interface may not be implemented on Linux.
    


## NAME



           semop — XSI semaphore operations
    


## SYNOPSIS



           #include <sys/sem.h>
    
           int semop(int _semid_ , struct sembuf *_sops_ , size_t _nsops_);
    


## DESCRIPTION



           The _semop_() function operates on XSI semaphores (see the Base
           Definitions volume of POSIX.1‐2017, _Section 4.17_ , _Semaphore_).  It
           is unspecified whether this function interoperates with the
           realtime interprocess communication facilities defined in _Section_
           _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_.
    
           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_ is
                   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 _semval_ is less than the absolute value of _sem_op_ and
                   (_sem_flg_ &IPC_NOWAIT) is non-zero, _semop_() shall return
                   immediately.
    
                *  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 until one of the
                   following conditions occurs:
    
                   --  The value of _semval_ becomes greater than or equal to
                       the absolute value of _sem_op_.  When this occurs, the
                       value of _semncnt_ associated with the specified
                       semaphore shall be decremented, the absolute value of
                       _sem_op_ shall be subtracted from _semval_ and, 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.
    
                   --  The _semid_ for which the calling thread is awaiting
                       action is removed from the system. When this occurs,
                       _errno_ shall be set to **[EIDRM]** and -1 shall be
                       returned.
    
                   --  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(3p).
    
            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.
    
            3. If _sem_op_ is 0 and the calling process has read permission,
               one of the following shall occur:
    
                *  If _semval_ is 0, _semop_() shall return immediately.
    
                *  If _semval_ is non-zero and (_sem_flg_ &IPC_NOWAIT) is non-
                   zero, _semop_() shall return immediately.
    
                *  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 until one of the following occurs:
    
                   --  The value of _semval_ becomes 0, at which time the value
                       of _semzcnt_ associated with the specified semaphore
                       shall be decremented.
    
                   --  The _semid_ for which the calling thread is awaiting
                       action is removed from the system. When this occurs,
                       _errno_ shall be set to **[EIDRM]** and -1 shall be
                       returned.
    
                   --  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(3p).
    
           Upon successful completion, the value of _sempid_ for each semaphore
           specified in the array pointed to by _sops_ shall be set to the
           process ID of the calling process. Also, the _sem_otime_ timestamp
           shall be set to the current time, as described in _Section 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
                  _Section 2.7_ , _XSI Interprocess Communication_.
    
           **EAGAIN** The operation would result in suspension of the calling
                  process 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 unique semaphore key using the _ftok_()
           function, then gets a semaphore ID associated with that key using
           the _semget_() function (the first call also tests to make sure the
           semaphore exists).  If the semaphore does not exist, the program
           creates it, as shown by the second call to _semget_().  In creating
           the semaphore for the queuing process, the program attempts to
           create one semaphore with read/write permission for all. It also
           uses the IPC_EXCL flag, which forces _semget_() to fail if the
           semaphore already exists.
    
           After creating the semaphore, the program uses calls to _semctl_()
           and _semop_() to initialize it to the values in the _sbuf_ array. The
           number of processes that can execute concurrently without queuing
           is initially set to 2. The final call to _semget_() creates a
           semaphore identifier that can be used later in the program.
    
           Processes that obtain _semid_ without creating it check that
           _sem_otime_ is non-zero, to ensure that the creating process has
           completed the _semop_() initialization.
    
           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 <stdio.h>
               #include <sys/sem.h>
               #include <sys/stat.h>
               #include <errno.h>
               #include <stdlib.h>
               ...
               key_t semkey;
               int semid;
               struct sembuf sbuf;
               union semun {
                   int val;
                   struct semid_ds *buf;
                   unsigned short *array;
               } arg;
               struct semid_ds ds;
               ...
               /* Get unique key for semaphore. */
               if ((semkey = ftok("/tmp", 'a')) == (key_t) -1) {
                   perror("IPC error: ftok"); exit(1);
               }
    
               /* Get semaphore ID associated with this key. */
               if ((semid = semget(semkey, 0, 0)) == -1) {
    
                   /* Semaphore does not exist - Create. */
                   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. */
                       arg.val = 0;
                       sbuf.sem_num = 0;
                       sbuf.sem_op = 2;  /* This is the number of runs without queuing. */
                       sbuf.sem_flg = 0;
                       if (semctl(semid, 0, SETVAL, arg) == -1
                           || semop(semid, &sbuf, 1) == -1) {
                           perror("IPC error: semop"); exit(1);
                       }
                   }
                   else if (errno == EEXIST) {
                       if ((semid = semget(semkey, 0, 0)) == -1) {
                           perror("IPC error 1: semget"); exit(1);
                       }
                       goto check_init;
                   }
                   else {
                       perror("IPC error 2: semget"); exit(1);
                   }
               }
               else
               {
                   /* Check that semid has completed initialization. */
                   /* An application can use a retry loop at this point rather than
                      exiting. */
                   check_init:
                   arg.buf = &ds;
                   if (semctl(semid, 0, IPC_STAT, arg) < 0) {
                       perror("IPC error 3: semctl"); exit(1);
                   }
                   if (ds.sem_otime == 0) {
                       perror("IPC error 4: semctl"); exit(1);
                   }
               }
               ...
               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 _Section 2.7_ , _XSI Interprocess Communication_
           can be easily modified to use the alternative interfaces.
    


## RATIONALE



           None.
    


## FUTURE DIRECTIONS



           None.
    


* * *