Semaphores

A semaphore is a synchronization object that limits the number of threads that can concurrently access a resource.

Anytime that a thread successfully acquires the semaphore using SEMAPHORE_Acquire(), its count is decremented by one. If the semaphore's count is zero when a thread attempts to acquire the semaphore, the calling thread will be blocked until the semaphore's count is incremented using SEMAPHORE_Release().

Unlike the mutex, a semaphore does not have the notion of an owner thread. Without an owner, any thread can release a semaphore, even if it is different than the thread that originally acquired the semaphore.

Basic Usage

The code snippet below demonstrates how to allocate and create a counting semaphore.

#include "Kernel/kernel_semaphore.h"
#include <assert.h>

static SEMAPHORE sem1;                      /* Allocate a semaphore */

void APP_Example(void)
{
    STATUS status;


    status = SEMAPHORE_Create(&sem1,        /* A pointer to the allocated semaphore to be created */
                              "Semaphore1", /* A name for the semaphore (debugging purposes) */
                              0,            /* The initial count for the semaphore */
                              10);          /* The maximum allowable count for the semaphore */

    assert(status == SUCCESS);
}

One of the typical uses of a counting semaphore is to use the semaphore to signal a thread each time an event has occurred. The semaphore can keep a count of events that are pending to be processed by the thread. The thread can then be notified of each event to be processed.

The code snippet below has an event handler that releases the semaphore each time that the event occurred which releases the thread that is blocked upon the semaphore. For each time the semaphore is released, the thread will successfully acquire the semaphore and the event can be processed (and counted). Note the semaphore was created with a maximum count of '10', which for this example means that only up to '10' events can be pending to be processed before the events will be dropped and not processed by the thread.

#include "Kernel/kernel_semaphore.h"
#include <assert.h>

void EventHandler(void)
{
    STATUS status;


    status = SEMAPHORE_Release(&sem1, 1);   /* Release the semaphore once per event */
    assert(status == SUCCESS);
}

void ExampleThread(void* arg)
{
    UINT32 count = 0;
    STATUS status;


    for(;;) {

        status = SEMAPHORE_Acquire(&sem1, INFINITE);    /* Wait until event handler releases semaphore */
        if (status == SUCCESS) {                        /* Was the semaphore successfully acquired? */
			
            ProcessEvent();                             /* Process the event */
            count++;                                    /* Keep count of events that have been processed */
        }
    }
}

API Reference

STATUS SEMAPHORE_Create(SEMAPHORE* sem, const CHAR* name, UINT32 initcnt, UINT32 maxcnt)
Creates and initializes a counting semaphore with the specified initial and maximum count value.
PARAMETERS
sem A pointer to a caller allocated semaphore to be initialized.
name A pointer to a NULL terminated string that represents a name for the semaphore.
initcnt The intial count value for the semaphore. Must be greater than or equal to zero, and must be less than or equal to 'maxcnt'.
maxcnt The maximum count value for the semaphore. Must be greater than zero.
RETURNS
SUCCESS The semaphore has been created and initialized.
ERR_NULLREFERENCE The argument 'sem' was found to be NULL.
ERR_INVALIDCONTEXT The operation is not supported from the context of an interrupt service routine (ISR).
ERR_INVALIDARGUMENT The argument 'initcnt' or 'maxcnt' was invalid.
ERR_ALREADYINITIALIZED The specified semaphore has already been created and initialized.
STATUS SEMAPHORE_Destroy(SEMAPHORE* sem)
Destroys and removes a semaphore from the kernel. Any threads that happen to be waiting to acquire the semaphore will be released with the ERR_DESTROYED status code.
PARAMETERS
sem A pointer to the semaphore to be destroyed.
RETURNS
SUCCESS The semaphore has been destroyed and removed from the kernel.
ERR_NULLREFERENCE The argument 'sem' was found to be NULL.
ERR_INVALIDCONTEXT The operation is not supported from the context of an interrupt service routine (ISR).
ERR_NOTINITIALIZED The specified semaphore has not been created and initialized.
STATUS SEMAPHORE_Acquire(SEMAPHORE* sem, UINT32 timeout)
Acquires a semaphore. If the semaphore's count is non-zero, the semaphore's count is decremented and the call returns without blocking. If the semaphore's count is zero, this call will block until the semaphore's count is incremented or until the specified timeout interval elapses.
PARAMETERS
sem A pointer to the semaphore to wait upon to be signaled.
timeout A maximum amount of time, in kernel ticks, to block and wait for the semaphore to become signaled. Use '0' to return immediately without blocking. Use 'INFINITE' to block indefinitely.
RETURNS
SUCCESS The semaphore has been acquired.
ERR_NULLREFERENCE The argument 'sem' was found to be NULL.
ERR_INVALIDCONTEXT The operation is not supported from the context of an interrupt service routine (ISR).
ERR_NOTINITIALIZED The specified semaphore has not been created and initialized.
ERR_TIMEOUT The timeout period has elapsed prior to the semaphore becoming signaled.
STATUS SEMAPHORE_Release(SEMAPHORE* sem, UINT32 count)
Releases a semaphore and increments the semaphore's count by the specified amount. If there are any threads blocked on the semaphore, each increment in the count can release one of the blocked threads.
PARAMETERS
sem A pointer to the semaphore to be released.
count The amount in which the specified semaphore's count should be increased. Must be greater than zero.
RETURNS
SUCCESS The semaphore has been released and its count has been updated.
ERR_NULLREFERENCE The argument 'sem' was found to be NULL.
ERR_INVALIDARGUMENT The argument 'count' was invalid. Must be greater than zero.
ERR_NOTINITIALIZED The specified semaphore has not been created and initialized.
UINT32 SEMAPHORE_Count(SEMAPHORE* sem)
Returns the current count for a semaphore.
PARAMETERS
sem A pointer to the target semaphore.
RETURNS
The current count for the specified semaphore.