Revise instructions to take advantage of the "public object" and "private object" terminology now covered in the kernel overview documentation. Also incorporates some missing information the users need to be aware of when defining certain object types. Change-Id: Ic0b359baf4443714c80200fdaff9cf2d253e6b99 Signed-off-by: Allan Stephens <allan.stephens@windriver.com>
243 lines
7.8 KiB
ReStructuredText
243 lines
7.8 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.
|
|
|
|
|
|
Public Semaphore
|
|
----------------
|
|
|
|
Define the semaphore in the application's .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
|
|
|
|
A public semaphore can be referenced from any source file that includes
|
|
the file :file:`zephyr.h`.
|
|
|
|
|
|
Private Semaphore
|
|
-----------------
|
|
|
|
Define the semaphore a source file using the following syntax:
|
|
|
|
.. code-block:: c
|
|
|
|
DEFINE_SEMAPHORE(name);
|
|
|
|
For example, the following code defines a private semaphore named ``PRIV_SEM``.
|
|
|
|
.. code-block:: c
|
|
|
|
DEFINE_SEMAPHORE(PRIV_SEM);
|
|
|
|
To utilize this semaphore from a different source file use the following syntax:
|
|
|
|
.. code-block:: c
|
|
|
|
extern const ksem_t PRIV_SEM;
|
|
|
|
|
|
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. |
|
|
+----------------------------------------------+------------------------------+
|