Change-Id: I13ad61239659a17768831290535f02787776282c Signed-off-by: Allan Stephens <allan.stephens@windriver.com>
217 lines
7.2 KiB
ReStructuredText
217 lines
7.2 KiB
ReStructuredText
.. _microkernel_semaphores:
|
|
|
|
Semaphores
|
|
**********
|
|
|
|
Definition
|
|
==========
|
|
|
|
The microkernel semaphore is defined in
|
|
:file:`kernel/microkernel/k_semaphore.c` and are an implementation of
|
|
traditional counting semaphores. Semaphores are used to synchronize
|
|
application task activities.
|
|
|
|
Function
|
|
========
|
|
|
|
Semaphores are initialized by the system. At start the semaphore is
|
|
un-signaled and no task is waiting for it. Any task in the system can
|
|
signal a semaphore. Every signal increments the count value associated
|
|
with the semaphore. When several tasks wait for the same semaphore at
|
|
the same time, they are held in a prioritized list. If the semaphore is
|
|
signaled, the task with the highest priority is released. If more tasks
|
|
of that priority are waiting, the first one that requested the
|
|
semaphore wakes up. Other tasks can test the semaphore to see if it is
|
|
signaled. If not signaled, tasks can either wait, with or without a
|
|
timeout, until signaled or return immediately with a failed status.
|
|
|
|
Usage
|
|
=====
|
|
|
|
Defining a Semaphore
|
|
--------------------
|
|
|
|
The following parameters must be defined:
|
|
|
|
*name*
|
|
This specifies a unique name for the semaphore.
|
|
|
|
|
|
Add an entry for a semaphore in the project .MDEF file using the
|
|
following syntax:
|
|
|
|
.. code-block:: console
|
|
|
|
SEMA %name
|
|
|
|
For example, the file :file:`projName.mdef` defines two semaphores
|
|
as follows:
|
|
|
|
.. code-block:: console
|
|
|
|
% SEMA NAME
|
|
% ================
|
|
SEMA INPUT_DATA
|
|
SEMA WORK_DONE
|
|
|
|
|
|
Example: Giving a Semaphore from a Task
|
|
---------------------------------------
|
|
|
|
This code uses a semaphore to indicate that a unit of data
|
|
is available for processing by a consumer task.
|
|
|
|
.. code-block:: c
|
|
|
|
void producer_task(void)
|
|
{
|
|
/* save data item in a buffer */
|
|
...
|
|
|
|
/* notify task that an additional data item is available */
|
|
task_sem_give(INPUT_DATA);
|
|
|
|
...
|
|
}
|
|
|
|
Example: Giving a Semaphore from an ISR
|
|
---------------------------------------
|
|
|
|
This code uses a semaphore to indicate that a unit of data
|
|
is available for processing by a consumer task.
|
|
|
|
.. code-block:: c
|
|
|
|
/*
|
|
* reserve 2 command packets for semaphore updates
|
|
*
|
|
* note: this assumes that input data arrives at a rate that allows
|
|
* the microkernel server fiber to finish the semaphore give operation
|
|
* for data item "N" before the ISR begins working on data item "N+2"
|
|
* (i.e. data arrives in bursts of at most one unit)
|
|
*/
|
|
static CMD_PKT_SET_INSTANCE(cmd_packets, 2);
|
|
|
|
void input_data_interrupt_handler(void *arg)
|
|
{
|
|
/* save data item in a buffer */
|
|
...
|
|
|
|
/* notify task that an additional data item is available */
|
|
isr_sem_give(INPUT_DATA, &CMD_PKT_SET(cmd_packets));
|
|
|
|
...
|
|
}
|
|
|
|
Example: Taking a Semaphore with a Conditional Time-out
|
|
-------------------------------------------------------
|
|
|
|
This code waits up to 500 ticks for a semaphore to be given,
|
|
and gives a warning if it is not obtained in that time.
|
|
|
|
.. code-block:: c
|
|
|
|
void consumer_task(void)
|
|
{
|
|
...
|
|
|
|
if (task_sem_take_wait_timeout(INPUT_DATA, 500) == RC_TIME) {
|
|
printf("Input data not available!");
|
|
} else {
|
|
/* extract saved data item from buffer and process it */
|
|
...
|
|
}
|
|
...
|
|
}
|
|
|
|
Example: Monitoring Multiple Semaphores at Once
|
|
-----------------------------------------------
|
|
|
|
This code waits on two semaphores simultaneously, and then takes
|
|
action depending on which one was given.
|
|
|
|
.. code-block:: c
|
|
|
|
ksem_t my_sem_group[3] = { INPUT_DATA, WORK_DONE, ENDLIST };
|
|
|
|
void consumer_task(void)
|
|
{
|
|
ksem_t sem_id;
|
|
...
|
|
|
|
sem_id = task_sem_group_take_wait(my_sem_group);
|
|
if (sem_id == WORK_DONE) {
|
|
printf("Shutting down!");
|
|
return;
|
|
} else {
|
|
/* process input data */
|
|
...
|
|
}
|
|
...
|
|
}
|
|
|
|
Example: Giving Multiple Semaphores at Once
|
|
-------------------------------------------
|
|
|
|
This code uses a semaphore group to allow a controlling task to signal
|
|
the semaphores used by four other tasks in a single operation.
|
|
|
|
.. code-block:: c
|
|
|
|
ksem_t my_sem_group[5] = { SEM1, SEM2, SEM3, SEM4, ENDLIST };
|
|
|
|
void control_task(void)
|
|
{
|
|
...
|
|
task_semaphore_group_give(my_sem_group);
|
|
...
|
|
}
|
|
|
|
|
|
APIs
|
|
====
|
|
|
|
The following APIs for an individual semaphore are provided by microkernel.h.
|
|
|
|
+----------------------------------------+------------------------------------+
|
|
| Call | Description |
|
|
+========================================+====================================+
|
|
| :c:func:`isr_sem_give()` | Signal a semaphore from an ISR. |
|
|
+----------------------------------------+------------------------------------+
|
|
| :c:func:`fiber_sem_give()` | Signal a semaphore from a fiber. |
|
|
+----------------------------------------+------------------------------------+
|
|
| :c:func:`task_sem_give()` | Signal a semaphore from a task. |
|
|
+----------------------------------------+------------------------------------+
|
|
| :c:func:`task_sem_take()` | Test a semaphore without waiting. |
|
|
+----------------------------------------+------------------------------------+
|
|
| :c:func:`task_sem_take_wait()` | Wait on a semaphore. |
|
|
+----------------------------------------+------------------------------------+
|
|
| :c:func:`task_sem_take_wait_timeout()` | Wait on a semaphore for a |
|
|
| | specified time period. |
|
|
+----------------------------------------+------------------------------------+
|
|
| :c:func:`task_sem_reset()` | Sets the semaphore count to zero. |
|
|
+----------------------------------------+------------------------------------+
|
|
| :c:func:`task_sem_count_get()` | Read signal count for a semaphore. |
|
|
+----------------------------------------+------------------------------------+
|
|
|
|
|
|
The following APIs for semaphore groups are provided by microkernel.h.
|
|
|
|
+----------------------------------------------+------------------------------+
|
|
| Call | Description |
|
|
+==============================================+==============================+
|
|
| :c:func:`task_sem_group_give()` | Signal a set of semaphores. |
|
|
+----------------------------------------------+------------------------------+
|
|
| :c:func:`task_sem_group_take()` | Test a set of semaphores |
|
|
| | without waiting. |
|
|
+----------------------------------------------+------------------------------+
|
|
| :c:func:`task_sem_group_take_wait()` | Wait on a set of semaphores. |
|
|
+----------------------------------------------+------------------------------+
|
|
| :c:func:`task_sem_group_take_wait_timeout()` | Wait on a set of semaphores |
|
|
| | for a specified time period. |
|
|
+----------------------------------------------+------------------------------+
|
|
| :c:func:`task_sem_group_reset()` | Sets the semaphore count to |
|
|
| | to zero for a set of |
|
|
| | semaphores. |
|
|
+----------------------------------------------+------------------------------+
|