Svsem

# 17. Svsem

Semaphores provide a mechanism to coordinate multiple processes or threads accessing shared resources. The svsem(3m) module provides a POSIX-like semaphore interface implemented using the more common System V semaphore interface.

The svsem(3m) module is not available in the Win32 environment.

### 17.1. Words of Caution

There are some tricky aspects to using System V semaphores that svsem(3m) attempts to deal with but some words of caution are in order. Both problems described here are attributed to the persistance of semaphores after a program has terminated. The robustness of an application using System V semaphores depends greatly on the diligence of the programmer to destroy or remove semaphores that should no longer be used. If a program terminiates without destroying or properly removing the semaphore it will be left open in the kernel. Open semaphores can be viewed with the `ipcs` command;

      shell$ ipcs -s
      ------ Semaphore Arrays --------
      key        semid      owner     perms      nsems      status
      0x0105b9cf 3080192    miallen   600        50

The svsem(3m) module is designed specifically to be robust and not to fail to create a semaphore if another semaphore with the same key already exists on the system. However, if `O_EXCL` is specified, it is possible that an old semphore will block the creation of a new semaphore. For robustness, it is recommended that the `svsem_create` function be used in favor of `svsem_open` because `svsem_create` uses mkstemp(3) to create a uniqe filename. Regardless, it may still be necessary to remove old semaphores with a command such as;

      shell$ ipcrm sem 3080192

A similar problem with System V semaphores occurs if a process terminiates abnormally while accessing semaphore protected resources shared by other processes. This can leave the application in an undesireable state such as leaving the resource perminantly locked. The `SEM_UNDO` flag of semop(2) is designed to assist with this problem. If `SEM_UNDO` is specified, when the program terminates, the semaphore value will be reset by reversing all effects of previous operations. This is a notoriously clumsy mechanism and it fails completely in one important case; if processes do not make symmetric calls to semop(2) the `SEM_UNDO` state will overflow and cause further calls to fail. For this reason the `SEM_UNDO` flag can only be used with symmetric calls (e.g. binary semaphores) such as;

      wait(sem)
      // SEM_UNDO is ok for sem because the calls are symmetric
      post(sem)

If the calls are asymmetric where one process calls `wait` and a different process calls `post` on the same semaphore (e.g. counting semaphores) eventually an errors will result. The svsem(3m) module can do nothing to resolve this issue directly but does permit the user to specify if `SEM_UNDO` is to be used.

### 17.2. Memory management functions

These functions should be used to create and destroy `svsem` semaphores and pools.

The `svsem_create` function
Synopsis

      #include <mba/svsem.h>
      int svsem_create(svsem_t *sem, int value, int undo);

Description
The `svsem_create` function will created a file using mkstemp(3) with a template of `/tmp/svsemXXXXXX` to generate a semaphore key, create and initialize a semaphore `sem` and set it's initial value to `value`. If `undo` is non-zero, the `SEM_UNDO` flag for semop calls will be used. The `undo` parameter should be non-zero for semaphores for which wait and post will be called symmetrically in any process such as binary semaphores. The `undo` flag must be zero if a process will call wait and post an un-equal number of times such as with counting semaphores.

Returns
If the operation is successful 0 is returned. Otherwise -1 is returned and `errno` is set appropriately.

The `svsem_destroy` function
Synopsis

      #include <mba/svsem.h>
      int svsem_destroy(svsem_t *sem);

Description
The `svsem_destroy` function destroys the semaphore `sem` by removing the semaphore set identifier and unlinking the associated file.
Returns
If the operation is successful 0 is returned. Otherwise -1 is returned and `errno` is set appropriately. Errors that occur attempting to unlink(3m) the associated file are ignored.

The `svsem_open` function
Synopsis

      #include <mba/svsem.h>
      int svsem_open(svsem_t *sem, const char *path, int oflag, ... /* mode_t mode, int value */);

Description
The `svsem_open` function creates a new named semaphore or opens an existing semaphore. The `path` parameter is a path (which must refer to an existing, accessible file) that identifies the target semaphore. The `oflag` paremeter can be 0, `O_CREAT`, or `O_CREAT | O_EXCL`. If `O_CREAT` is specified two additional parameters are required;

- a `mode_t` paramter specifying the open mode (e.g. 0600) and
- an `int` parameter specifying the initial value of the semaphore (e.g. 1 for a binary semaphore).

If `O_CREAT` is specified without `O_EXCL` the semaphore is created and initialized with the specified value if it does not already exist. If the semaphore already exists it is simply opened. Use the `SEM_UNDO` flag OR'd with `oflags` to specify that undo behavior should be used (recommended unless calls to wait/post are not symetric per process).
Returns
The `svsem_open` function returns 0 if the new semaphore was created successfully or `NULL` if an error occurs in which case `errno` will be set appropriately. If `O_EXCL` is specified and the semaphore already exists, `NULL` is returned and `errno` is set to `EEXIST`.

The `svsem_close` function
Synopsis

      #include <mba/svsem.h>
      int svsem_close(svsem_t *sem);

Description
The `svsem_close` function does nothing but release the memory attributed to `sem`.
Returns
If the operation is successful 0 is returned. Otherwise -1 is returned and `errno` is set appropriately.

The `svsem_remove` function
Synopsis

      #include <mba/svsem.h>
      int svsem_remove(svsem_t *sem);

Description
The `svsem_remove` function removes the semaphore identified by `sem`. Any attempt to access this semaphore after it has been remove will result in all operations returning an error of `EIDRM`.
Returns
The `svsem_remove` function returns 0 if the operation was successful or -1 if an error occured in which case `errno` will be set appropriately.

The `svsem_pool_create` function
Synopsis

      #include <mba/svsem.h>
      int svsem_pool_create(struct pool *p,
               unsigned int max_size,
               unsigned int value,
               int undo,
               struct allocator *al);

Description
The `svsem_pool_create` function will create a pool of semaphores. A file will be created using mkstemp(3) with a template of `/tmp/svsemXXXXXX`, a semaphore array of `max_size` will be created and all semaphores will be initialized to the specified `value`. No initial svsem(3m) objects are created. The pool(3m) functions are used to manage the pool. The `pool_get` function will return a semaphore initialized to `value` (reused semaphores will be explicitly reset). The `svsem_pool_destroy` function must be used to destroy an svsem(3m) pool.
Returns
If the operation is successful 0 is returned. Otherwise -1 is returned and `errno` is set appropriately.

The `svsem_pool_destroy` function
Synopsis

      #include <mba/svsem.h>
      int svsem_pool_destroy(struct pool *p);

Description
The `svsem_pool_destroy` function releases memory associated with the pool, removes the pool semaphore array and unlinks the file backing the array.
Returns
If the operation is successful 0 is returned. Otherwise -1 is returned and `errno` is set appropriately.

### 17.3. Svsem functions

These functions should be used to manipulate svsem(3m) semaphores.

The `svsem_wait` function
Synopsis

      #include <mba/svsem.h>
      int svsem_wait(svsem_t *sem);

Description
The `svsem_wait` function tests the value of the semaphore identified by `sem` and does one of two things;

- If the value is greater than 0, the value is decremented by 1 and the function returns immediately.
- If the value is 0 the calling thread will sleep until svsem_post is called on the semaphore at which point the value will be tested again.

Returns
If the operation is successful 0 is returned. Otherwise -1 is returned and `errno` is set appropriately.

The `svsem_trywait` function
Synopsis

      #include <mba/svsem.h>
      int svsem_trywait(svsem_t *sem);

Description
The `svsem_trywait` function tests the value of the semaphore identified by `sem` and does one of two things;

- If the value is greater than 0, the value is decremented by 1 and the function returns immediately.
- If the value is 0 the call will return -1 and set `errno` to `EAGAIN`.

This mechanism can be used to test if a thread will wait.
Returns
If the operation is successful 0 is returned. Otherwise -1 is returned and `errno` is set appropriately.

The `svsem_post` function
Synopsis

      #include <mba/svsem.h>
      int svsem_post(svsem_t *sem);

Description
The `svsem_post` function increments the value of the semaphore identified by `sem` by 1 and wakes up a thread blocked in `svsem_wait` if there is one.
Returns
If the operation is successful 0 is returned. Otherwise -1 is returned and `errno` is set appropriately.

The `svsem_post_multiple` function
Synopsis

      #include <mba/svsem.h>
      int svsem_post_multiple(svsem_t *sem, int count);

Description
The `svsem_post_multiple` function performs the equivalent of multiple distinct `svsem_post` operations. The `count` parameter specifies how many post operations are performed.
Returns
If the operation is successful 0 is returned. Otherwise -1 is returned and `errno` is set appropriately.

The `svsem_getvalue` function
Synopsis

      #include <mba/svsem.h>
      int svsem_getvalue(svsem_t *sem, int *value);

Description
The `svsem_getvalue` function stores the value of the semaphore `sem` into `value`.
Returns
If the operation is successful 0 is returned. Otherwise -1 is returned and `errno` is set appropriately.

The `svsem_setvalue` function
Synopsis

      #include <mba/svsem.h>
      int svsem_setvalue(svsem_t *sem, int value);

Description
The `svsem_setvalue` function sets the current value of the semaphore to the specified `value`.
Returns
If the operation is successful 0 is returned. Otherwise -1 is returned and `errno` is set appropriately.

Copyright 2004 Michael B. Allen <mba2000 ioplex.com>