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. |
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. |
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. |
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. |
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. |
The current count for the specified semaphore.