2016-09-03 03:54:16 +08:00
|
|
|
.. _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 32-bit data values.
|
|
|
|
|
|
|
|
.. contents::
|
|
|
|
:local:
|
|
|
|
:depth: 2
|
|
|
|
|
|
|
|
Concepts
|
|
|
|
********
|
|
|
|
|
|
|
|
Any number of stacks can be defined. Each stack is referenced
|
|
|
|
by its memory address.
|
|
|
|
|
|
|
|
A stack has the following key properties:
|
|
|
|
|
|
|
|
* A **queue** of 32-bit data values that have been added but not yet removed.
|
|
|
|
The queue is implemented using an array of 32-bit integers,
|
|
|
|
and must be aligned on a 4-byte boundary.
|
|
|
|
|
|
|
|
* 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.
|
|
|
|
The kernel does *not* detect attempts to add a data value to a stack
|
|
|
|
that has already reached its maximum quantity of queued values.
|
|
|
|
|
|
|
|
.. note::
|
|
|
|
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:type:`struct k_stack`.
|
|
|
|
It must then be initialized by calling :cpp:func:`k_stack_init()`.
|
|
|
|
|
|
|
|
The following code defines and initializes an empty stack capable of holding
|
|
|
|
up to ten 32-bit data values.
|
|
|
|
|
|
|
|
.. code-block:: c
|
|
|
|
|
|
|
|
#define MAX_ITEMS 10
|
|
|
|
|
|
|
|
uint32_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
|
2016-11-16 22:44:58 +08:00
|
|
|
by calling :c:macro:`K_STACK_DEFINE`.
|
2016-09-03 03:54:16 +08:00
|
|
|
|
|
|
|
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 :cpp: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, (uint32_t)&my_buffers[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
Popping from a Stack
|
|
|
|
====================
|
|
|
|
|
|
|
|
A data item is taken from a stack by calling :cpp: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;
|
|
|
|
|
2016-10-18 01:06:48 +08:00
|
|
|
k_stack_pop(&buffer_stack, (uint32_t *)&new_buffer, K_FOREVER);
|
2016-09-03 03:54:16 +08:00
|
|
|
new_buffer->field1 = ...
|
|
|
|
|
|
|
|
Suggested Uses
|
|
|
|
**************
|
|
|
|
|
|
|
|
Use a 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.
|
|
|
|
|
|
|
|
Configuration Options
|
|
|
|
*********************
|
|
|
|
|
|
|
|
Related configuration options:
|
|
|
|
|
|
|
|
* None.
|
|
|
|
|
|
|
|
APIs
|
|
|
|
****
|
|
|
|
|
|
|
|
The following stack APIs are provided by :file:`kernel.h`:
|
|
|
|
|
2016-11-16 22:44:58 +08:00
|
|
|
* :c:macro:`K_STACK_DEFINE`
|
2016-09-03 03:54:16 +08:00
|
|
|
* :cpp:func:`k_stack_init()`
|
|
|
|
* :cpp:func:`k_stack_push()`
|
|
|
|
* :cpp:func:`k_stack_pop()`
|