EtcPal  HEAD (unstable)
ETC Platform Abstraction Layer (EtcPal)
View other versions:
sem (Counting Semaphores)

Overview

Counting semaphore objects.

#include "etcpal/sem.h"

A counting semaphore is a synchronization value which can never fall below zero. Each time the semaphore is posted, its count increases. Each time the semaphore is taken, its count decreases, unless the count is zero, in which case the task waiting for it is blocked until it is posted again. This is often used for tracking events that can occur multiple times before being serviced or pools of resources.

Usage example:

static etcpal_sem_t sem;
#define SEM_MAX_COUNT 20
void main(void)
{
etcpal_sem_create(&sem, 0, SEM_MAX_COUNT);
// Enable interrupts
while (1)
{
if (etcpal_sem_wait(&sem))
{
// Service the interrupt.
// Because this is a counting semaphore, we will enter this block once for each time the
// interrupt is received.
}
}
return 0;
}
void interrupt_handler(void)
{
// We've received some event via interrupt.
// Notify the service thread that a new event has occurred.
}
bool etcpal_sem_create(etcpal_sem_t *id, unsigned int initial_count, unsigned int max_count)
Create a new counting semaphore.
PLATFORM_DEFINED etcpal_sem_t
The semaphore identifier.
Definition: sem.dox:73
void etcpal_sem_destroy(etcpal_sem_t *id)
Destroy a semaphore object.
bool etcpal_sem_post_from_isr(etcpal_sem_t *id)
Post a semaphore from an interrupt context.
bool etcpal_sem_wait(etcpal_sem_t *id)
Wait for a semaphore.

etcpal_sem implementations use different constructs under the hood on various platforms. Also, different platforms affect the behavior of certain functions.

Platform ETCPAL_SEM_HAS_TIMED_WAIT ETCPAL_SEM_HAS_POST_FROM_ISR ETCPAL_SEM_HAS_MAX_COUNT ETCPAL_SEM_MUST_BE_BALANCED Underlying Type
FreeRTOS Yes Yes Yes No Counting Semaphores
Linux No No No No POSIX Semaphores
macOS No No No Yes Dispatch Semaphores
MQX Yes No No No Lightweight Semaphores
Windows Yes No Yes No Semaphore objects
Zephyr Yes Yes Yes No Semaphores

Macros

#define ETCPAL_SEM_HAS_TIMED_WAIT   /* platform-defined */
 Whether etcpal_sem_timed_wait() is meaningful on this platform. More...
 
#define ETCPAL_SEM_HAS_POST_FROM_ISR   /* platform-defined */
 Whether etcpal_sem_post_from_isr() is meaningful on this platform. More...
 
#define ETCPAL_SEM_HAS_MAX_COUNT   /* platform-defined */
 Whether counting semaphores have a maximum count on this platform. More...
 
#define ETCPAL_SEM_MUST_BE_BALANCED   /* platform-defined */
 Whether the semaphore must have its initial count before being destroyed. More...
 

Typedefs

typedef PLATFORM_DEFINED etcpal_sem_t
 The semaphore identifier. More...
 

Functions

bool etcpal_sem_create (etcpal_sem_t *id, unsigned int initial_count, unsigned int max_count)
 Create a new counting semaphore. More...
 
bool etcpal_sem_wait (etcpal_sem_t *id)
 Wait for a semaphore. More...
 
bool etcpal_sem_try_wait (etcpal_sem_t *id)
 Try to wait for a semaphore. More...
 
bool etcpal_sem_timed_wait (etcpal_sem_t *id, int timeout_ms)
 Wait for a semaphore, giving up after a timeout. More...
 
bool etcpal_sem_post (etcpal_sem_t *id)
 Post a semaphore. More...
 
bool etcpal_sem_post_from_isr (etcpal_sem_t *id)
 Post a semaphore from an interrupt context. More...
 
void etcpal_sem_destroy (etcpal_sem_t *id)
 Destroy a semaphore object. More...
 

Macro Definition Documentation

◆ ETCPAL_SEM_HAS_MAX_COUNT

#define ETCPAL_SEM_HAS_MAX_COUNT   /* platform-defined */

Whether counting semaphores have a maximum count on this platform.

Some platforms have a maximum count after which a counting semaphore can no longer be posted. If defined to 0, the max_count argument to etcpal_sem_create() is ignored.

◆ ETCPAL_SEM_HAS_POST_FROM_ISR

#define ETCPAL_SEM_HAS_POST_FROM_ISR   /* platform-defined */

Whether etcpal_sem_post_from_isr() is meaningful on this platform.

Some platforms have a different method for posting a signal from an interrupt context. If defined to 0, etcpal_sem_post_from_isr() executes the equivalent of etcpal_sem_post().

◆ ETCPAL_SEM_HAS_TIMED_WAIT

#define ETCPAL_SEM_HAS_TIMED_WAIT   /* platform-defined */

Whether etcpal_sem_timed_wait() is meaningful on this platform.

If defined to 0, etcpal_sem_timed_wait() executes the equivalent of etcpal_sem_try_wait() if given a timeout of 0, or etcpal_sem_wait() otherwise.

◆ ETCPAL_SEM_MUST_BE_BALANCED

#define ETCPAL_SEM_MUST_BE_BALANCED   /* platform-defined */

Whether the semaphore must have its initial count before being destroyed.

Currently the only platform for which this is true is macOS. Calls to etcpal_sem_wait() and friends must be balanced with calls to etcpal_sem_post() and friends. If the semaphore does not have its initial count when being destroyed, an EXC_BAD_INSTRUCTION exception is raised.

Typedef Documentation

◆ etcpal_sem_t

typedef PLATFORM_DEFINED etcpal_sem_t

The semaphore identifier.

Depending on the platform, this could be a scalar type or a struct.

Function Documentation

◆ etcpal_sem_create()

bool etcpal_sem_create ( etcpal_sem_t id,
unsigned int  initial_count,
unsigned int  max_count 
)

Create a new counting semaphore.

If initial_count is 0, calls to etcpal_sem_wait() will block until the first call is made to etcpal_sem_post().

Parameters
[out]idSemaphore identifier on which to create a semaphore. If this function returns true, *id becomes valid for calls to other etcpal_sem API functions.
[in]initial_countThe count value assigned to the semaphore when it is created.
[in]max_countThe maximum count that the semaphore can have. This is not meaningful on all platforms - see ETCPAL_SEM_HAS_MAX_COUNT. If it is meaningful, once the count reaches this value, the semaphore can no longer be posted.
Returns
true: The semaphore was created.
false: The semaphore was not created.

◆ etcpal_sem_destroy()

void etcpal_sem_destroy ( etcpal_sem_t id)

Destroy a semaphore object.

NOTE: if ETCPAL_SEM_MUST_BE_BALANCED is defined to 1, the semaphore must have its initial count before being destroyed.

Parameters
[in]idIdentifier for the semaphore to destroy.

◆ etcpal_sem_post()

bool etcpal_sem_post ( etcpal_sem_t id)

Post a semaphore.

If the count is zero and there is a thread waiting for the semaphore, wakes up the thread without incrementing the count. Otherwise, increments the count, unless the count is equal to the value provided for max_count when the semaphore was created, in which case it returns false. (note: the max_count behavior does not occur on all platforms. See the table in the module overview for more information).

Parameters
[in]idIdentifier for the semaphore to post.
Returns
true: The semaphore was posted.
false: The semaphore has hit its maximum count, the semaphore was invalid or an error occurred.

◆ etcpal_sem_post_from_isr()

bool etcpal_sem_post_from_isr ( etcpal_sem_t id)

Post a semaphore from an interrupt context.

This function is only meaningful on some platforms; namely, those which have a different method for posting a semaphore from an interrupt context. The value of ETCPAL_SEM_HAS_POST_FROM_ISR can be used to determine whether this function is meaningful on the current platform. If it is defined to 0, this function simply executes the equivalent of etcpal_sem_post().

Parameters
[in]idIdentifier for the semaphore to post.
Returns
true: The semaphore was posted.
false: The semaphore has hit its maximum count, the semaphore was invalid or an error occurred.

◆ etcpal_sem_timed_wait()

bool etcpal_sem_timed_wait ( etcpal_sem_t id,
int  timeout_ms 
)

Wait for a semaphore, giving up after a timeout.

If the semaphore's count is nonzero, decrements the count and returns true. Otherwise, waits up to timeout_ms for the semaphore to be posted, returning false if this timeout expires.

This function is not honored on all platforms. The value of ETCPAL_SEM_HAS_TIMED_WAIT can be used to determine whether this function is honored on the current platform. If it is defined to 0, this function executes the equivalent of etcpal_sem_try_wait() if timeout_ms is 0, or etcpal_sem_wait() otherwise.

Parameters
[in]idIdentifier for the semaphore for which to wait.
[in]timeout_msMaximum amount of time to wait for the semaphore, in milliseconds. If ETCPAL_WAIT_FOREVER is given, the result is the same as if etcpal_sem_wait() was called.
Returns
true: The semaphore's count was decremented.
false: The timeout expired while the semaphore's count was zero, the semaphore was invalid or an error occurred.

◆ etcpal_sem_try_wait()

bool etcpal_sem_try_wait ( etcpal_sem_t id)

Try to wait for a semaphore.

If the semaphore's count is nonzero, decrements the count and returns true. Otherwise, returns false immediately.

Parameters
[in]idIdentifier for the semaphore for which to attempt to wait.
Returns
true: The semaphore's count was decremented.
false: The semaphore's count was zero, the semaphore is invalid or an error occurred.

◆ etcpal_sem_wait()

bool etcpal_sem_wait ( etcpal_sem_t id)

Wait for a semaphore.

If the semaphore's count is nonzero, decrements the count and returns true. Otherwise, blocks until a call to etcpal_sem_post() on the semaphore.

Parameters
[in]idIdentifier for the semaphore for which to wait.
Returns
true: The semaphore's count was decremented.
false: The semaphore is invalid or an error occurred.