143 lines
4.2 KiB
ReStructuredText
143 lines
4.2 KiB
ReStructuredText
.. _stacks_v2:
|
|
|
|
Stacks
|
|
######
|
|
|
|
A :dfn:`stack` is a kernel object that implements a traditional
|
|
last in, first out (LIFO) queue, allowing threads and ISRs
|
|
to add and remove a limited number of integer data values.
|
|
|
|
.. contents::
|
|
:local:
|
|
:depth: 2
|
|
|
|
Concepts
|
|
********
|
|
|
|
Any number of stacks can be defined (limited only by available RAM). Each stack
|
|
is referenced by its memory address.
|
|
|
|
A stack has the following key properties:
|
|
|
|
* A **queue** of integer data values that have been added but not yet removed.
|
|
The queue is implemented using an array of stack_data_t values
|
|
and must be aligned on a native word boundary.
|
|
The stack_data_t type corresponds to the native word size i.e. 32 bits or
|
|
64 bits depending on the CPU architecture and compilation mode.
|
|
|
|
* A **maximum quantity** of data values that can be queued in the array.
|
|
|
|
A stack must be initialized before it can be used. This sets its queue to empty.
|
|
|
|
A data value can be **added** to a stack by a thread or an ISR.
|
|
The value is given directly to a waiting thread, if one exists;
|
|
otherwise the value is added to the LIFO's queue.
|
|
|
|
.. note::
|
|
If :kconfig:`CONFIG_NO_RUNTIME_CHECKS` is enabled, the kernel will *not* detect
|
|
and prevent attempts to add a data value to a stack that has already reached
|
|
its maximum quantity of queued values. Adding a data value to a stack that is
|
|
already full will result in array overflow, and lead to unpredictable behavior.
|
|
|
|
A data value may be **removed** from a stack by a thread.
|
|
If the stack's queue is empty a thread may choose to wait for it to be given.
|
|
Any number of threads may wait on an empty stack simultaneously.
|
|
When a data item is added, it is given to the highest priority thread
|
|
that has waited longest.
|
|
|
|
.. note::
|
|
The kernel does allow an ISR to remove an item from a stack, however
|
|
the ISR must not attempt to wait if the stack is empty.
|
|
|
|
Implementation
|
|
**************
|
|
|
|
Defining a Stack
|
|
================
|
|
|
|
A stack is defined using a variable of type :c:struct:`k_stack`.
|
|
It must then be initialized by calling :c:func:`k_stack_init` or
|
|
:c:func:`k_stack_alloc_init`. In the latter case, a buffer is not
|
|
provided and it is instead allocated from the calling thread's resource
|
|
pool.
|
|
|
|
The following code defines and initializes an empty stack capable of holding
|
|
up to ten word-sized data values.
|
|
|
|
.. code-block:: c
|
|
|
|
#define MAX_ITEMS 10
|
|
|
|
stack_data_t my_stack_array[MAX_ITEMS];
|
|
struct k_stack my_stack;
|
|
|
|
k_stack_init(&my_stack, my_stack_array, MAX_ITEMS);
|
|
|
|
Alternatively, a stack can be defined and initialized at compile time
|
|
by calling :c:macro:`K_STACK_DEFINE`.
|
|
|
|
The following code has the same effect as the code segment above. Observe
|
|
that the macro defines both the stack and its array of data values.
|
|
|
|
.. code-block:: c
|
|
|
|
K_STACK_DEFINE(my_stack, MAX_ITEMS);
|
|
|
|
Pushing to a Stack
|
|
==================
|
|
|
|
A data item is added to a stack by calling :c:func:`k_stack_push`.
|
|
|
|
The following code builds on the example above, and shows how a thread
|
|
can create a pool of data structures by saving their memory addresses
|
|
in a stack.
|
|
|
|
.. code-block:: c
|
|
|
|
/* define array of data structures */
|
|
struct my_buffer_type {
|
|
int field1;
|
|
...
|
|
};
|
|
struct my_buffer_type my_buffers[MAX_ITEMS];
|
|
|
|
/* save address of each data structure in a stack */
|
|
for (int i = 0; i < MAX_ITEMS; i++) {
|
|
k_stack_push(&my_stack, (stack_data_t)&my_buffers[i]);
|
|
}
|
|
|
|
Popping from a Stack
|
|
====================
|
|
|
|
A data item is taken from a stack by calling :c:func:`k_stack_pop`.
|
|
|
|
The following code builds on the example above, and shows how a thread
|
|
can dynamically allocate an unused data structure.
|
|
When the data structure is no longer required, the thread must push
|
|
its address back on the stack to allow the data structure to be reused.
|
|
|
|
.. code-block:: c
|
|
|
|
struct my_buffer_type *new_buffer;
|
|
|
|
k_stack_pop(&buffer_stack, (stack_data_t *)&new_buffer, K_FOREVER);
|
|
new_buffer->field1 = ...
|
|
|
|
Suggested Uses
|
|
**************
|
|
|
|
Use a stack to store and retrieve integer data values in a "last in,
|
|
first out" manner, when the maximum number of stored items is known.
|
|
|
|
Configuration Options
|
|
*********************
|
|
|
|
Related configuration options:
|
|
|
|
* None.
|
|
|
|
API Reference
|
|
*************
|
|
|
|
.. doxygengroup:: stack_apis
|