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>
244 lines
7.9 KiB
ReStructuredText
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. |
|
|
+----------------------------------------------+------------------------------+
|