Stacks¶
A 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.
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. 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 k_stack
.
It must then be initialized by calling k_stack_init()
or
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.
#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 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.
K_STACK_DEFINE(my_stack, MAX_ITEMS);
Pushing to a Stack¶
A data item is added to a stack by calling 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.
/* 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 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.
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.
API Reference¶
-
group
stack_apis
Defines
-
K_STACK_DEFINE
(name, stack_num_entries)¶ Statically define and initialize a stack.
The stack can be accessed outside the module where it is defined using:
extern struct k_stack <name>;
- Parameters
name
: Name of the stack.stack_num_entries
: Maximum number of values that can be stacked.
-
K_KERNEL_STACK_DEFINE
(sym, size)¶ Define a toplevel kernel stack memory region.
This declares a region of memory for use as a thread stack, for threads that exclusively run in supervisor mode. This is also suitable for declaring special stacks for interrupt or exception handling.
Stacks declared with this macro may not host user mode threads.
It is legal to precede this definition with the ‘static’ keyword.
It is NOT legal to take the sizeof(sym) and pass that to the stackSize parameter of k_thread_create(), it may not be the same as the ‘size’ parameter. Use K_KERNEL_STACK_SIZEOF() instead.
The total amount of memory allocated may be increased to accommodate fixed-size stack overflow guards.
- Parameters
sym
: Thread stack symbol namesize
: Size of the stack memory region
-
K_KERNEL_STACK_ARRAY_DEFINE
(sym, nmemb, size)¶ Define a toplevel array of kernel stack memory regions.
Stacks declared with this macro may not host user mode threads.
- Parameters
sym
: Kernel stack array symbol namenmemb
: Number of stacks to declaresize
: Size of the stack memory region
-
K_KERNEL_STACK_MEMBER
(sym, size)¶ Declare an embedded stack memory region.
Used for kernel stacks embedded within other data structures.
Stacks declared with this macro may not host user mode threads.
- Parameters
sym
: Thread stack symbol namesize
: Size of the stack memory region
-
K_KERNEL_STACK_SIZEOF
(sym)¶
-
K_THREAD_STACK_SIZEOF
(sym)¶ Return the size in bytes of a stack memory region.
Convenience macro for passing the desired stack size to k_thread_create() since the underlying implementation may actually create something larger (for instance a guard area).
The value returned here is not guaranteed to match the ‘size’ parameter passed to K_THREAD_STACK_DEFINE and may be larger, but is always safe to pass to k_thread_create() for the associated stack object.
- Return
Size of the stack buffer
- Parameters
sym
: Stack memory symbol
-
K_THREAD_STACK_DEFINE
(sym, size)¶ Declare a toplevel thread stack memory region.
This declares a region of memory suitable for use as a thread’s stack.
This is the generic, historical definition. Align to Z_THREAD_STACK_OBJ_ALIGN and put in ‘noinit’ section so that it isn’t zeroed at boot
The declared symbol will always be a k_thread_stack_t which can be passed to k_thread_create(), but should otherwise not be manipulated. If the buffer inside needs to be examined, examine thread->stack_info for the associated thread object to obtain the boundaries.
It is legal to precede this definition with the ‘static’ keyword.
It is NOT legal to take the sizeof(sym) and pass that to the stackSize parameter of k_thread_create(), it may not be the same as the ‘size’ parameter. Use K_THREAD_STACK_SIZEOF() instead.
Some arches may round the size of the usable stack region up to satisfy alignment constraints. K_THREAD_STACK_SIZEOF() will return the aligned size.
- Parameters
sym
: Thread stack symbol namesize
: Size of the stack memory region
-
K_THREAD_STACK_LEN
(size)¶ Calculate size of stacks to be allocated in a stack array.
This macro calculates the size to be allocated for the stacks inside a stack array. It accepts the indicated “size” as a parameter and if required, pads some extra bytes (e.g. for MPU scenarios). Refer K_THREAD_STACK_ARRAY_DEFINE definition to see how this is used. The returned size ensures each array member will be aligned to the required stack base alignment.
- Return
Appropriate size for an array member
- Parameters
size
: Size of the stack memory region
-
K_THREAD_STACK_ARRAY_DEFINE
(sym, nmemb, size)¶ Declare a toplevel array of thread stack memory regions.
Create an array of equally sized stacks. See K_THREAD_STACK_DEFINE definition for additional details and constraints.
This is the generic, historical definition. Align to Z_THREAD_STACK_OBJ_ALIGN and put in ‘noinit’ section so that it isn’t zeroed at boot
- Parameters
sym
: Thread stack symbol namenmemb
: Number of stacks to declaresize
: Size of the stack memory region
-
K_THREAD_STACK_MEMBER
(sym, size)¶ Declare an embedded stack memory region.
Used for stacks embedded within other data structures. Use is highly discouraged but in some cases necessary. For memory protection scenarios, it is very important that any RAM preceding this member not be writable by threads else a stack overflow will lead to silent corruption. In other words, the containing data structure should live in RAM owned by the kernel.
A user thread can only be started with a stack defined in this way if the thread starting it is in supervisor mode.
This is now deprecated, as stacks defined in this way are not usable from user mode. Use K_KERNEL_STACK_MEMBER.
- Parameters
sym
: Thread stack symbol namesize
: Size of the stack memory region
Functions
-
void
k_stack_init
(struct k_stack *stack, stack_data_t *buffer, uint32_t num_entries)¶ Initialize a stack.
This routine initializes a stack object, prior to its first use.
- Return
N/A
- Parameters
stack
: Address of the stack.buffer
: Address of array used to hold stacked values.num_entries
: Maximum number of values that can be stacked.
-
int32_t
k_stack_alloc_init
(struct k_stack *stack, uint32_t num_entries)¶ Initialize a stack.
This routine initializes a stack object, prior to its first use. Internal buffers will be allocated from the calling thread’s resource pool. This memory will be released if k_stack_cleanup() is called, or userspace is enabled and the stack object loses all references to it.
- Return
-ENOMEM if memory couldn’t be allocated
- Parameters
stack
: Address of the stack.num_entries
: Maximum number of values that can be stacked.
-
int
k_stack_cleanup
(struct k_stack *stack)¶ Release a stack’s allocated buffer.
If a stack object was given a dynamically allocated buffer via k_stack_alloc_init(), this will free it. This function does nothing if the buffer wasn’t dynamically allocated.
- Parameters
stack
: Address of the stack.
- Return Value
0
: on success-EAGAIN
: when object is still in use
-
int
k_stack_push
(struct k_stack *stack, stack_data_t data)¶ Push an element onto a stack.
This routine adds a stack_data_t value data to stack.
- Note
Can be called by ISRs.
- Parameters
stack
: Address of the stack.data
: Value to push onto the stack.
- Return Value
0
: on success-ENOMEM
: if stack is full
-
int
k_stack_pop
(struct k_stack *stack, stack_data_t *data, k_timeout_t timeout)¶ Pop an element from a stack.
This routine removes a stack_data_t value from stack
in a “last in,
first out” manner and stores the value in
data.- Note
Can be called by ISRs, but timeout must be set to K_NO_WAIT.
- Parameters
stack
: Address of the stack.data
: Address of area to hold the value popped from the stack.timeout
: Waiting period to obtain a value, or one of the special values K_NO_WAIT and K_FOREVER.
- Return Value
0
: Element popped from stack.-EBUSY
: Returned without waiting.-EAGAIN
: Waiting period timed out.
-