#include <cyg/kernel/kapi.h> |
void cyg_semaphore_init
(cyg_sem_t* sem, cyg_count32 val);
void cyg_semaphore_destroy
(cyg_sem_t* sem);
cyg_bool_t cyg_semaphore_wait
(cyg_sem_t* sem);
cyg_bool_t cyg_semaphore_timed_wait
(cyg_sem_t* sem, cyg_tick_count_t abstime);
cyg_bool_t cyg_semaphore_trywait
(cyg_sem_t* sem);
void cyg_semaphore_post
(cyg_sem_t* sem);
void cyg_semaphore_peek
(cyg_sem_t* sem, cyg_count32* val);
Counting semaphores are a synchronization primitive that allow threads to wait until an event has occurred. The event may be generated by a producer thread, or by a DSR in response to a hardware interrupt. Associated with each semaphore is an integer counter that keeps track of the number of events that have not yet been processed. If this counter is zero, an attempt by a consumer thread to wait on the semaphore will block until some other thread or a DSR posts a new event to the semaphore. If the counter is greater than zero then an attempt to wait on the semaphore will consume one event, in other words decrement the counter, and return immediately. Posting to a semaphore will wake up the first thread that is currently waiting, which will then resume inside the semaphore wait operation and decrement the counter again.
Another use of semaphores is for certain forms of resource management. The counter would correspond to how many of a certain type of resource are currently available, with threads waiting on the semaphore to claim a resource and posting to release the resource again. In practice condition variables are usually much better suited for operations like this.
cyg_semaphore_init
is used to initialize a
semaphore. It takes two arguments, a pointer to a
cyg_sem_t
structure and an initial value for
the counter. Note that semaphore operations, unlike some other parts
of the kernel API, use pointers to data structures rather than
handles. This makes it easier to embed semaphores in a larger data
structure. The initial counter value can be any number, zero, positive
or negative, but typically a value of zero is used to indicate that no
events have occurred yet.
cyg_semaphore_wait
is used by a consumer thread
to wait for an event. If the current counter is greater than 0, in
other words if the event has already occurred in the past, then the
counter will be decremented and the call will return immediately.
Otherwise the current thread will be blocked until there is a
cyg_semaphore_post
call.
cyg_semaphore_post
is called when an event has
occurs. This increments the counter and wakes up the first thread
waiting on the semaphore (if any). Usually that thread will then
continue running inside cyg_semaphore_wait
and
decrement the counter again. However other scenarioes are possible.
For example the thread calling cyg_semaphore_post
may be running at high priority, some other thread running at medium
priority may be about to call cyg_semaphore_wait
when it next gets a chance to run, and a low priority thread may be
waiting on the semaphore. What will happen is that the current high
priority thread continues running until it is descheduled for some
reason, then the medium priority thread runs and its call to
cyg_semaphore_wait
succeeds immediately, and
later on the low priority thread runs again, discovers a counter value
of 0, and blocks until another event is posted. If there are multiple
threads blocked on a semaphore then the configuration option
CYGIMP_KERNEL_SCHED_SORTED_QUEUES
determines which
one will be woken up by a post operation.
cyg_semaphore_wait
returns a boolean. Normally it
will block until it has successfully decremented the counter, retrying
as necessary, and return success. However the wait operation may be
aborted by a call to cyg_thread_release
,
and cyg_semaphore_wait
will then return false.
cyg_semaphore_timed_wait
is a variant of
cyg_semaphore_wait
. It can be used to wait until
either an event has occurred or a number of clock ticks have happened.
The number of ticks is specified as an absolute, not relative tick
count, and so in order to wait for a relative number of ticks, the
return value of the cyg_current_time()
function
should be added to determine the absolute number of ticks. The
function returns success if the semaphore wait operation succeeded, or
false if the operation timed out or was aborted by
cyg_thread_release
.
If support for the real-time
clock has been removed from the current configuration then this
function will not be available.
cyg_semaphore_trywait
is another variant which
will always return immediately rather than block, again returning
success or failure. If cyg_semaphore_timedwait
is given a timeout in the past, it operates like
cyg_semaphore_trywait
.
cyg_semaphore_peek
can be used to get hold of the
current counter value. This function is rarely useful except for
debugging purposes since the counter value may change at any time if
some other thread or a DSR performs a semaphore operation.
cyg_semaphore_init
is normally called during
initialization but may also be called from thread context.
cyg_semaphore_wait
and
cyg_semaphore_timed_wait
may only be called from
thread context because these operations may block.
cyg_semaphore_trywait
,
cyg_semaphore_post
and
cyg_semaphore_peek
may be called from thread or
DSR context.