| .. _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 :c: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. |