zephyr/doc/kernel/microkernel/microkernel_semaphores.rst
Rodrigo Caballero 4d8b60adca Doc: Change the Microkernel Objects to the Microkernel Services section.
Moves the Microkernel Object documentation to a new Microkernel Services
section within the Kernel Primer. Labels, cross-references, figures,
headings and filenames were updated to reflect the new structure. 

Change-Id: Ia2a91410a94caa8a97bb8211db5afc84b5dc0974
Signed-off-by: Rodrigo Caballero <rodrigo.caballero.abraham@intel.com>
2016-02-05 20:15:19 -05:00

244 lines
7.9 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 in MDEF file
=================================
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
Defining Semaphore Inside Code
==============================
In addition to defining semaphores in MDEF file, it is also possible to
define semaphores inside code. The macro ``DEFINE_SEMAPHORE(sem_name)``
can be used for this purpose.
For example, the following code can be used to define a global semaphore
``PRIV_SEM``.
.. code-block:: c
DEFINE_SEMAPHORE(PRIV_SEM);
The semaphore ``PRIV_SEM`` can be used in the same style as those
semaphores defined in MDEF file.
It is possible to utilize this semaphore in another source file, simply
add:
.. code-block:: c
extern const ksem_t PRIV_SEM;
to that file. The semaphore ``PRIV_SEM`` can be then used there.
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. |
+----------------------------------------------+------------------------------+