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 errors will ensue. 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 any combination of 0, O_CREAT, O_EXCL, and O_UNDO or'd together although O_EXCL is only meaningful when used with O_CREAT. If O_CREAT is specified two additional parameters are required; 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 O_UNDO flag to specify that SEM_UNDO behavior should be used (recommended unless calls to wait/post are not symetric per process).

Note: It appears that trying to open an existing semaphore on Mac OS X will deadlock because Darwin is not initializing sem_otime properly. This requires futher investigation.
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;
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; 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>