blob: fa0d752fa979a944c6fe9fabdc2a6525559badbb [file] [log] [blame]
.. _nanokernel_stacks:
Nanokernel Stacks
#################
Concepts
********
The nanokernel's stack object type is an implementation of a traditional
last in, first out queue for a limited number of 32-bit data values.
It is mainly intended for use by fibers.
Each stack uses an array of 32-bit words to hold its data values. The array
may be of any size, but must be aligned on a 4-byte boundary.
Any number of nanokernel stacks can be defined. Each stack is a distinct
variable of type :c:type:`struct nano_stack`, and is referenced using a pointer
to that variable. A stack must be initialized to use its array before it
can be used to send or receive data values.
Data values can be added to a stack in a non-blocking manner by any context type
(i.e. ISR, fiber, or task).
.. note::
A context must not attempt to add a data value to a stack whose array
is already full, as the resulting array overflow will lead to
unpredictable behavior.
Data values can be removed from a stack in a non-blocking manner by any context
type; if the stack is empty a special return code indicates that no data value
was removed. Data values can also be removed from a stack in a blocking manner
by a fiber or task; if the stack is empty the fiber or task waits for a data
value to be added.
Only a single fiber, but any number of tasks, may wait on an empty nanokernel
stack simultaneously. When a data value becomes available it is given to the
waiting fiber, or to a waiting task if no fiber is waiting.
.. note::
The nanokernel does not allow more than one fiber to wait on a nanokernel
stack. If a second fiber starts waiting the first waiting fiber is
superseded and ends up waiting forever.
A task that waits on an empty nanokernel stack does a busy wait. This is
not an issue for a nanokernel application's background task; however, in
a microkernel application a task that waits on a nanokernel stack remains
the current task. In contrast, a microkernel task that waits on a
microkernel data passing object ceases to be the current task, allowing
other tasks of equal or lower priority to do useful work.
If multiple tasks in a microkernel application wait on the same nanokernel
stack, higher priority tasks are given data values in preference to lower
priority tasks. However, the order in which equal priority tasks are given
data values is unpredictable.
Purpose
*******
Use a nanokernel stack to store and retrieve 32-bit data values in a "last in,
first out" manner, when the maximum number of stored items is known.
Usage
*****
Example: Initializing a Nanokernel Stack
========================================
This code establishes an empty nanokernel stack capable of holding
up to 10 items.
.. code-block:: c
#define MAX_ALARMS 10
struct nano_stack alarm_stack;
uint32_t stack_area[MAX_ALARMS];
...
nano_stack_init(&alarm_stack, stack_area);
Example: Writing to a Nanokernel Stack
======================================
This code shows how an ISR can use a nanokernel stack to pass a 32-bit alarm
indication to a processing fiber.
.. code-block:: c
#define OVERHEAT_ALARM 17
void overheat_interrupt_handler(void *arg)
{
...
/* report alarm */
nano_isr_stack_push(&alarm_stack, OVERHEAT_ALARM);
...
}
Example: Reading from a Nanokernel Stack
========================================
This code shows how a fiber can use a nanokernel stack to retrieve 32-bit alarm
indications signalled by other parts of the application,
such as ISRs and other fibers. It is assumed that the fiber can handle
bursts of alarms before the stack overflows, and that the order
in which alarms are processed isn't significant.
.. code-block:: c
void alarm_handler_fiber(int arg1, int arg2)
{
uint32_t alarm_number;
while (1) {
/* wait for an alarm to be reported */
alarm_number = nano_fiber_stack_pop(&alarm_stack, TICKS_UNLIMITED);
/* process alarm indication */
...
}
}
APIs
****
The following APIs for a nanokernel stack are provided by
:file:`nanokernel.h`:
:cpp:func:`nano_stack_init()`
Initializes a stack.
:cpp:func:`nano_task_stack_push()`, :cpp:func:`nano_fiber_stack_push()`,
:cpp:func:`nano_isr_stack_push()`, :cpp:func:`nano_stack_push()`
Add an item to a stack.
:cpp:func:`nano_task_stack_pop()`, :cpp:func:`nano_fiber_stack_pop()`,
:cpp:func:`nano_isr_stack_pop()`, :cpp:func:`nano_stack_pop()`
Remove an item from a stack, or wait for an item if it is empty.