home *** CD-ROM | disk | FTP | other *** search
- /*
- ** $VER: unixsem.c 1.0 (05 Mar 95)
- **
- ** UNIX like counting semaphores for the AMIGA
- **
- ** (C) Copyright 1995 Marius Gröger
- ** All Rights Reserved
- **
- ** $HISTORY:
- **
- ** 05 Mar 1995 : 001.000 : created
- */
-
- #ifndef CLIB_ALIB_PROTOS_H
- #include <clib/alib_protos.h>
- #endif
- #ifndef CLIB_EXEC_PROTOS_H
- #include <clib/exec_protos.h>
- #include <pragmas/exec_pragmas.h>
- #endif
-
- #include "unixsem.h"
-
- /* private structure to maintain tasks within the waiting space of a semaphore */
- struct semachain
- {
- struct MinNode link; /* std exec minimal node */
- struct Task *this; /* the task waiting to get granted a semaphore unit */
- ULONG sigmask; /* the task waits for this exec signal */
- };
-
- /* Initialize a semaphore for use. This sets various private fields.
- The user may provide an Exec style signal-mask which should be used
- for waiting operertions concerning THIS semaphore. If signal is
- equal to -1, the default signal-mask UNIXSEM_SIGMASK is used. This
- is defined in "unixsem.h" and may be altered with succeeding recompilation
- of ALL modules using the semaphore calls.
- The unit counter is set to zero.
- */
- extern VOID
- sinit(
- CountSemaphore *sem /* pointer to a semaphore */,
- ULONG sigmask /* exec signal-mask to be used for waiting
- operations or -1 to used UNIXSEM_SIGMASK */
- )
- {
- InitSemaphore(&sem->sem_Lock);
- NewList((struct List*)&sem->sem_WaitingSpace);
- sem->sem_Count = 0;
- sem->sem_SigMask = (sigmask != (ULONG)(-1)) ? sigmask : UNIXSEM_SIGMASK;
- }
-
- /* Set a semaphore to a certain value. This is done independent of
- any task possibly waiting fo the semaphore. Therefore this function
- should only be called prior to any call of ssignal() or swait().
- To create a mutual exclusion semaphore for protected areas of code,
- te following sequence is appropriate:
-
- sinit(&mutex,-1);
- sset(&mutex,1);
-
- Anybody who wants to enter the protected area later should
- perform these steps:
-
- swait(&mutex);
- // protected area here
- ssignal(&mutex);
-
- This has, of course, the same result as an according ObainSemaphore()/
- ReleaseSemaphore() construct, but might be useful when porting UNIX
- applications.
- */
- extern VOID sset(
- CountSemaphore *sem /* pointer to a semaphore */,
- LONG val /* value the semaphore should be assigned */
- )
- {
- /* always single-threaden the semaphore access */
- ObtainSemaphore(&sem->sem_Lock);
- sem->sem_Count = val;
- ReleaseSemaphore(&sem->sem_Lock);
- }
-
- /* Increment the unit counter of a semaphore. If there are any tasks waiting
- for a unit, the chronologically first waiter will be awakened.
- */
- extern VOID ssignal(
- CountSemaphore *sem /* pointer to a semaphore */
- )
- {
- struct semachain *sc;
-
- /* always single-threaden the semaphore access */
- ObtainSemaphore(&sem->sem_Lock);
-
- /* add a unit, have to wake up somebody ? */
- if (sem->sem_Count++ < 0)
- {
- /* there MUST be at least one waiter! */
- sc = (struct semachain*)RemHead((struct List*)&sem->sem_WaitingSpace);
- Signal(sc->this, sc->sigmask);
- }
-
- ReleaseSemaphore(&sem->sem_Lock);
- }
-
- /* Decrement the unit count of a semaphore. If the unit count before the
- call to swait() was less or equal to zero, the task will be added
- to the semaphore's waiting space and fall asleep until sombody
- calls ssignal() to the semaphore. If there are already other tasks
- within the waiting space, these will be waked up first, before your
- task is.
- */
-
- extern VOID swait(
- CountSemaphore *sem /* pointer to a semaphore */
- )
- {
- struct semachain sc;
- BOOL sleep;
-
- ObtainSemaphore(&sem->sem_Lock);
- /* get a unit, go to sleep ? */
- if (--sem->sem_Count < 0)
- {
- /* delay the Wait() till after ReleaseSemaphore() */
- sleep = TRUE;
- sc.sigmask = sem->sem_SigMask;
- sc.this = FindTask(NULL);
- AddTail((struct List*)&sem->sem_WaitingSpace, (struct Node*)&sc.link);
- }
- else
- {
- sleep = FALSE;
- }
- ReleaseSemaphore(&sem->sem_Lock);
-
- /*
- ** Note: maybe we are now de-queued again by a concurrent ssignal()
- ** and got the exec-signal before we Wait() for it. This is ok.
- ** Fortunatly, it is not possible for us to have more than
- ** one semachain pending, as this would be a bit trickier to
- ** handle (exec signals do not nest).
- */
- if (sleep) Wait(sem->sem_SigMask);
- }
-
-