<interface name="svsem"
	short="POSIX-like semaphores implemented using SysV semaphores.">

<comments>
	Copyright 2004 Michael B. Allen &lt;mba2000 ioplex.com&gt;
</comments>

<include>mba/svsem.h</include>

<title>Svsem</title>
<desc>
Semaphores provide a mechanism to coordinate multiple processes or threads accessing shared resources. The <def>svsem</def>(3m) module provides a POSIX-like semaphore interface implemented using the more common System V semaphore interface.
<p/>
The <def>svsem</def>(3m) module is not available in the Win32 environment.
</desc>

<group>
<title>Words of Caution</title>
<desc>
There are some tricky aspects to using System V semaphores that <def>svsem</def>(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 <tt>ipcs</tt> command;
<pre>
shell$ ipcs -s 
------ Semaphore Arrays --------
key        semid      owner     perms      nsems      status      
0x0105b9cf 3080192    miallen   600        50
</pre>
The <def>svsem</def>(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 <tt>O_EXCL</tt> is specified, it is possible that an old semphore will block the creation of a new semaphore. For robustness, it is recommended that the <ident>svsem_create</ident> function be used in favor of <ident>svsem_open</ident> because <ident>svsem_create</ident> uses <def>mkstemp</def>(3) to create a uniqe filename. Regardless, it may still be necessary to remove old semaphores with a command such as;
<pre>
shell$ ipcrm sem 3080192
</pre>
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 <tt>SEM_UNDO</tt> flag of <def>semop</def>(2) is designed to assist with this problem. If <tt>SEM_UNDO</tt> 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 <def>semop</def>(2) the <tt>SEM_UNDO</tt> state will overflow and cause further calls to fail. For this reason the <tt>SEM_UNDO</tt> flag can only be used with symmetric calls (e.g. binary semaphores) such as;
<pre>
wait(sem)
// SEM_UNDO is ok for sem because the calls are symmetric
post(sem)
</pre>
If the calls are asymmetric where one process calls <tt>wait</tt> and a different process calls <tt>post</tt> on the same semaphore (e.g. counting semaphores) eventually an errors will result. The <def>svsem</def>(3m) module can do nothing to resolve this issue directly but does permit the user to specify if <tt>SEM_UNDO</tt> is to be used.
</desc>
</group>


<group>
<title>Memory management functions</title>
<desc>These functions should be used to create and destroy <ident>svsem</ident> semaphores and pools.</desc>
<!--          *     *     *          -->
<meth name="create">
	<pre>int svsem_create(svsem_t *sem, int value, int undo);</pre>
	<param name="sem"/>
	<param name="value"/>
	<param name="undo"/>
	<desc>
The <ident>svsem_create</ident> function will created a file using <def>mkstemp</def>(3) with a template of <tt>/tmp/svsemXXXXXX</tt> to generate a semaphore key, create and initialize a semaphore <tt>sem</tt> and set it's initial value to <tt>value</tt>. If <tt>undo</tt> is non-zero, the <tt>SEM_UNDO</tt> flag for <def>semop</def> calls will be used. The <tt>undo</tt> parameter should be non-zero for semaphores for which wait and post will be called symmetrically in any process such as binary semaphores. The <tt>undo</tt> flag must be zero if a process will call wait and post an un-equal number of times such as with counting semaphores.
<p/>
	</desc>
	<ret>
If the operation is successful 0 is returned. Otherwise -1 is returned and <tt>errno</tt> is set appropriately.
	</ret>
</meth>
<!--          *     *     *          -->
<meth name="destroy">
	<pre>int svsem_destroy(svsem_t *sem);</pre>
	<param name="sem"/>
	<desc>
The <ident>svsem_destroy</ident> function destroys the semaphore <tt>sem</tt> by removing the semaphore set identifier and unlinking the associated file.
	</desc>
	<ret>
If the operation is successful 0 is returned. Otherwise -1 is returned and <tt>errno</tt> is set appropriately. Errors that occur attempting to <def>unlink</def>(3m) the associated file are ignored.
	</ret>
</meth>
<!--          *     *     *          -->
<meth name="open">
	<pre>int svsem_open(svsem_t *sem, const char *path, int oflag, ... /* mode_t mode, int value */);</pre>
	<param name="sem"/>
	<param name="path"/>
	<param name="oflag"/>
	<desc>
The <ident>svsem_open</ident> function creates a new named semaphore or opens an existing semaphore. The <tt>path</tt> parameter is a path (which must refer to an existing, accessible file) that identifies the target semaphore. The <tt>oflag</tt> paremeter can be 0, <tt>O_CREAT</tt>, or <tt>O_CREAT | O_EXCL</tt>. If <tt>O_CREAT</tt> is specified two additional parameters are required;
<ul>
<li>a <tt>mode_t</tt> paramter specifying the open mode (e.g. 0600) and</li>
<li>an <tt>int</tt> parameter specifying the initial value of the semaphore (e.g. 1 for a binary semaphore).</li>
</ul>
If <tt>O_CREAT</tt> is specified without <tt>O_EXCL</tt> 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 <tt>SEM_UNDO</tt> flag OR'd with <tt>oflags</tt> to specify that undo behavior should be used (recommended unless calls to wait/post are not symetric per process).
	</desc>
	<ret>
The <ident>svsem_open</ident> function returns 0 if the new semaphore was created successfully or <ident>NULL</ident> if an error occurs in which case <tt>errno</tt> will be set appropriately. If <tt>O_EXCL</tt> is specified and the semaphore already exists, <ident>NULL</ident> is returned and <tt>errno</tt> is set to <tt>EEXIST</tt>.
	</ret>
</meth>
<!--          *     *     *          -->
<meth name="close">
	<pre>int svsem_close(svsem_t *sem);</pre>
	<param name="sem"/>
	<desc>
The <ident>svsem_close</ident> function does nothing but release the memory attributed to <tt>sem</tt>.
	</desc>
	<ret>
If the operation is successful 0 is returned. Otherwise -1 is returned and <tt>errno</tt> is set appropriately.
	</ret>
</meth>
<!--          *     *     *          -->
<meth name="remove">
	<pre>int svsem_remove(svsem_t *sem);</pre>
	<param name="sem"/>
	<desc>
The <ident>svsem_remove</ident> function removes the semaphore identified by <tt>sem</tt>. Any attempt to access this semaphore after it has been remove will result in all operations returning an error of <tt>EIDRM</tt>.
	</desc>
	<ret>
The <ident>svsem_remove</ident> function returns 0 if the operation was successful or -1 if an error occured in which case <tt>errno</tt> will be set appropriately.
	</ret>
</meth>
<!--          *     *     *          -->
<meth name="pool_create" wrap="true">
	<pre>int svsem_pool_create(struct pool *p, unsigned int max_size, unsigned int value, int undo, struct allocator *al);</pre>
	<param name="p"/>
	<param name="max_size"/>
	<param name="value"/>
	<param name="undo"/>
	<param name="al"/>
	<desc>
The <ident>svsem_pool_create</ident> function will create a pool of semaphores. A file will be created using <def>mkstemp</def>(3) with a template of <tt>/tmp/svsemXXXXXX</tt>, a semaphore array of <tt>max_size</tt> will be created and all semaphores will be initialized to the specified <tt>value</tt>. No initial <def>svsem</def>(3m) objects are created. The <def>pool</def>(3m) functions are used to manage the pool. The <ident>pool_get</ident> function will return a semaphore initialized to <tt>value</tt> (reused semaphores will be explicitly reset). The <ident>svsem_pool_destroy</ident> function must be used to destroy an <def>svsem</def>(3m) pool.
	</desc>
	<ret>
If the operation is successful 0 is returned. Otherwise -1 is returned and <tt>errno</tt> is set appropriately.
	</ret>
</meth>
<!--          *     *     *          -->
<meth name="pool_destroy">
	<pre>int svsem_pool_destroy(struct pool *p);</pre>
	<param name="p"/>
	<desc>
The <ident>svsem_pool_destroy</ident> function releases memory associated with the pool, removes the pool semaphore array and unlinks the file backing the array.
	</desc>
	<ret>
If the operation is successful 0 is returned. Otherwise -1 is returned and <tt>errno</tt> is set appropriately.
	</ret>
</meth>
</group>


<group>
<title>Svsem functions</title>
<desc>These functions should be used to manipulate <def>svsem</def>(3m) semaphores.</desc>
<!--          *     *     *          -->
<meth name="wait">
	<pre>int svsem_wait(svsem_t *sem);</pre>
	<param name="sem"/>
	<desc>
The <ident>svsem_wait</ident> function tests the value of the semaphore identified by <tt>sem</tt> and does one of two things;
<ul>
<li>If the value is greater than 0, the value is decremented by 1 and the function returns immediately.</li>
<li>If the value is 0 the calling thread will sleep until <ident>svsem_post</ident> is called on the semaphore at which point the value will be tested again.</li>
</ul>
	</desc>
	<ret>
If the operation is successful 0 is returned. Otherwise -1 is returned and <tt>errno</tt> is set appropriately.
	</ret>
</meth>
<!--          *     *     *          -->
<meth name="trywait">
	<pre>int svsem_trywait(svsem_t *sem);</pre>
	<param name="sem"/>
	<desc>
The <ident>svsem_trywait</ident> function tests the value of the semaphore identified by <tt>sem</tt> and does one of two things;
<ul>
<li>If the value is greater than 0, the value is decremented by 1 and the function returns immediately.</li>
<li>If the value is 0 the call will return -1 and set <tt>errno</tt> to <tt>EAGAIN</tt>.</li>
</ul>
This mechanism can be used to test if a thread will wait.
	</desc>
	<ret>
If the operation is successful 0 is returned. Otherwise -1 is returned and <tt>errno</tt> is set appropriately.
	</ret>
</meth>
<!--          *     *     *          -->
<meth name="post">
	<pre>int svsem_post(svsem_t *sem);</pre>
	<param name="sem"/>
	<desc>
The <ident>svsem_post</ident> function increments the value of the semaphore identified by <tt>sem</tt> by 1 and wakes up a thread blocked in <ident>svsem_wait</ident> if there is one.
	</desc>
	<ret>
If the operation is successful 0 is returned. Otherwise -1 is returned and <tt>errno</tt> is set appropriately.
	</ret>
</meth>
<!--          *     *     *          -->
<meth name="post_multiple">
	<pre>int svsem_post_multiple(svsem_t *sem, int count);</pre>
	<param name="sem"/>
	<param name="count"/>
	<desc>
The <ident>svsem_post_multiple</ident> function performs the equivalent of multiple distinct <ident>svsem_post</ident> operations. The <tt>count</tt> parameter specifies how many post operations are performed.
	</desc>
	<ret>
If the operation is successful 0 is returned. Otherwise -1 is returned and <tt>errno</tt> is set appropriately.
	</ret>
</meth>
<!--          *     *     *          -->
<meth name="getvalue">
	<pre>int svsem_getvalue(svsem_t *sem, int *value);</pre>
	<param name="sem"/>
	<param name="value"/>
	<desc>
The <ident>svsem_getvalue</ident> function stores the value of the semaphore <tt>sem</tt> into <tt>value</tt>.
	</desc>
	<ret>
If the operation is successful 0 is returned. Otherwise -1 is returned and <tt>errno</tt> is set appropriately.
	</ret>
</meth>
<!--          *     *     *          -->
<meth name="setvalue">
	<pre>int svsem_setvalue(svsem_t *sem, int value);</pre>
	<param name="sem"/>
	<param name="value"/>
	<desc>
The <ident>svsem_setvalue</ident> function sets the current value of the semaphore to the specified <tt>value</tt>.
	</desc>
	<ret>
If the operation is successful 0 is returned. Otherwise -1 is returned and <tt>errno</tt> is set appropriately.
	</ret>
</meth>
</group>

</interface>
