131 lines
4.1 KiB
ReStructuredText
131 lines
4.1 KiB
ReStructuredText
.. _nanokernel_synchronization:
|
|
|
|
Synchronization Services
|
|
########################
|
|
|
|
This section describes synchronization services provided by the nanokernel.
|
|
Currently, only a single service is provided.
|
|
|
|
.. _nanokernel_semaphores:
|
|
|
|
Nanokernel Semaphores
|
|
*********************
|
|
|
|
Concepts
|
|
========
|
|
|
|
The nanokernel's :dfn:`semaphore` object type is an implementation of a
|
|
traditional counting semaphore. It is mainly intended for use by fibers.
|
|
|
|
Any number of nanokernel semaphores can be defined. Each semaphore is a
|
|
distinct variable of type :cpp:type:`struct nano_sem`, and is referenced
|
|
using a pointer to that variable. A semaphore must be initialized before
|
|
it can be used.
|
|
|
|
A nanokernel semaphore's count is set to zero when the semaphore is initialized.
|
|
This count is incremented each time the semaphore is given, and is decremented
|
|
each time the semaphore is taken. However, a semaphore cannot be taken if it is
|
|
unavailable; that is, when it has a count of zero.
|
|
|
|
A nanokernel semaphore may be **given** by any context type: ISRs, fibers,
|
|
or tasks.
|
|
|
|
A nanokernel semaphore may be **taken in a non-blocking manner** by any
|
|
context type; a special return code indicates if the semaphore is unavailable.
|
|
A semaphore can also be **taken in a blocking manner** by a fiber or task;
|
|
if the semaphore is unavailable, the thread waits for it to be given.
|
|
|
|
Any number of threads may wait on an unavailable nanokernel semaphore
|
|
simultaneously. When the semaphore is signaled, it is given to the fiber
|
|
that has waited longest, or to a waiting task when no fiber is waiting.
|
|
|
|
.. note::
|
|
A task that waits on an unavailable nanokernel FIFO semaphore busy-waits.
|
|
This is not an issue for a nanokernel application's background task;
|
|
however, in a microkernel application a task that waits on a nanokernel
|
|
semaphore remains the current task. In contrast, a microkernel task that
|
|
waits on a microkernel synchronization object ceases to be the current task,
|
|
allowing other tasks of equal or lower priority to do useful work.
|
|
|
|
When multiple tasks in a microkernel application are waiting on the same nanokernel
|
|
semaphore, higher priority tasks are given the semaphore in preference to
|
|
lower priority tasks. However, the order in which equal priority tasks are given
|
|
the semaphore is unpredictable.
|
|
|
|
Purpose
|
|
=======
|
|
|
|
Use a nanokernel semaphore to control access to a set of resources by multiple
|
|
fibers.
|
|
|
|
Use a nanokernel semaphore to synchronize processing between a producing task and
|
|
fiber, or among an ISR and one or more consuming fibers.
|
|
|
|
Usage
|
|
=====
|
|
|
|
Example: Initializing a Nanokernel Semaphore
|
|
--------------------------------------------
|
|
|
|
This code initializes a nanokernel semaphore, setting its count to zero.
|
|
|
|
.. code-block:: c
|
|
|
|
struct nano_sem input_sem;
|
|
|
|
nano_sem_init(&input_sem);
|
|
|
|
Example: Giving a Nanokernel Semaphore from an ISR
|
|
--------------------------------------------------
|
|
|
|
This code uses a nanokernel semaphore to indicate that a unit of data
|
|
is available for processing by a consumer fiber.
|
|
|
|
.. code-block:: c
|
|
|
|
void input_data_interrupt_handler(void *arg)
|
|
{
|
|
/* notify fiber that data is available */
|
|
nano_isr_sem_give(&input_sem);
|
|
|
|
...
|
|
}
|
|
|
|
Example: Taking a Nanokernel Semaphore with a Conditional Time-out
|
|
------------------------------------------------------------------
|
|
|
|
This code waits up to 500 ticks for a nanokernel semaphore to be given,
|
|
and gives warning if it is not obtained in that time.
|
|
|
|
.. code-block:: c
|
|
|
|
void consumer_fiber(void)
|
|
{
|
|
...
|
|
|
|
if (nano_fiber_sem_take(&input_sem, 500) != 1) {
|
|
printk("Input data not available!");
|
|
} else {
|
|
/* fetch available data */
|
|
...
|
|
}
|
|
...
|
|
}
|
|
|
|
APIs
|
|
====
|
|
|
|
The following APIs for a nanokernel semaphore are provided
|
|
by :file:`nanokernel.h`:
|
|
|
|
:cpp:func:`nano_sem_init()`
|
|
Initialize a semaphore.
|
|
|
|
:cpp:func:`nano_task_sem_give()`, :cpp:func:`nano_fiber_sem_give()`,
|
|
:cpp:func:`nano_isr_sem_give()`, :cpp:func:`nano_sem_give()`
|
|
Signal a sempahore.
|
|
|
|
:cpp:func:`nano_task_sem_take()`, :cpp:func:`nano_fiber_sem_take()`,
|
|
:cpp:func:`nano_isr_sem_take()`, :cpp:func:`nano_sem_take()`
|
|
Wait on a semaphore for a specified time period.
|