155 lines
4.5 KiB
ReStructuredText
155 lines
4.5 KiB
ReStructuredText
.. _memory_slabs_v2:
|
|
|
|
Memory Slabs
|
|
############
|
|
|
|
A :dfn:`memory slab` is a kernel object that allows memory blocks
|
|
to be dynamically allocated from a designated memory region.
|
|
All memory blocks in a memory slab have a single fixed size,
|
|
allowing them to be allocated and released efficiently
|
|
and avoiding memory fragmentation concerns.
|
|
|
|
.. contents::
|
|
:local:
|
|
:depth: 2
|
|
|
|
Concepts
|
|
********
|
|
|
|
Any number of memory slabs can be defined. Each memory slab is referenced
|
|
by its memory address.
|
|
|
|
A memory slab has the following key properties:
|
|
|
|
* The **block size** of each block, measured in bytes.
|
|
It must be at least 4N bytes long, where N is greater than 0.
|
|
|
|
* The **number of blocks** available for allocation.
|
|
It must be greater than zero.
|
|
|
|
* A **buffer** that provides the memory for the memory slab's blocks.
|
|
It must be at least "block size" times "number of blocks" bytes long.
|
|
|
|
The memory slab's buffer must be aligned to an N-byte boundary, where
|
|
N is a power of 2 larger than 2 (i.e. 4, 8, 16, ...). To ensure that
|
|
all memory blocks in the buffer are similarly aligned to this boundary,
|
|
the block size must also be a multiple of N.
|
|
|
|
A memory slab must be initialized before it can be used. This marks all of
|
|
its blocks as unused.
|
|
|
|
A thread that needs to use a memory block simply allocates it from a memory
|
|
slab. When the thread finishes with a memory block,
|
|
it must release the block back to the memory slab so the block can be reused.
|
|
|
|
If all the blocks are currently in use, a thread can optionally wait
|
|
for one to become available.
|
|
Any number of threads may wait on an empty memory slab simultaneously;
|
|
when a memory block becomes available, it is given to the highest-priority
|
|
thread that has waited the longest.
|
|
|
|
Unlike a heap, more than one memory slab can be defined, if needed. This
|
|
allows for a memory slab with smaller blocks and others with larger-sized
|
|
blocks. Alternatively, a memory pool object may be used.
|
|
|
|
Internal Operation
|
|
==================
|
|
|
|
A memory slab's buffer is an array of fixed-size blocks,
|
|
with no wasted space between the blocks.
|
|
|
|
The memory slab keeps track of unallocated blocks using a linked list;
|
|
the first 4 bytes of each unused block provide the necessary linkage.
|
|
|
|
Implementation
|
|
**************
|
|
|
|
Defining a Memory Slab
|
|
======================
|
|
|
|
A memory slab is defined using a variable of type :c:type:`struct k_mem_slab`.
|
|
It must then be initialized by calling :cpp:func:`k_mem_slab_init()`.
|
|
|
|
The following code defines and initializes a memory slab that has 6 blocks
|
|
that are 400 bytes long, each of which is aligned to a 4-byte boundary..
|
|
|
|
.. code-block:: c
|
|
|
|
struct k_mem_slab my_slab;
|
|
char __aligned(4) my_slab_buffer[6 * 400];
|
|
|
|
k_mem_slab_init(&my_slab, my_slab_buffer, 400, 6);
|
|
|
|
Alternatively, a memory slab can be defined and initialized at compile time
|
|
by calling :c:macro:`K_MEM_SLAB_DEFINE`.
|
|
|
|
The following code has the same effect as the code segment above. Observe
|
|
that the macro defines both the memory slab and its buffer.
|
|
|
|
.. code-block:: c
|
|
|
|
K_MEM_SLAB_DEFINE(my_slab, 400, 6, 4);
|
|
|
|
Allocating a Memory Block
|
|
=========================
|
|
|
|
A memory block is allocated by calling :cpp:func:`k_mem_slab_alloc()`.
|
|
|
|
The following code builds on the example above, and waits up to 100 milliseconds
|
|
for a memory block to become available, then fills it with zeroes.
|
|
A warning is printed if a suitable block is not obtained.
|
|
|
|
.. code-block:: c
|
|
|
|
char *block_ptr;
|
|
|
|
if (k_mem_slab_alloc(&my_slab, &block_ptr, 100) == 0)) {
|
|
memset(block_ptr, 0, 400);
|
|
...
|
|
} else {
|
|
printf("Memory allocation time-out");
|
|
}
|
|
|
|
Releasing a Memory Block
|
|
========================
|
|
|
|
A memory block is released by calling :cpp:func:`k_mem_slab_free()`.
|
|
|
|
The following code builds on the example above, and allocates a memory block,
|
|
then releases it once it is no longer needed.
|
|
|
|
.. code-block:: c
|
|
|
|
char *block_ptr;
|
|
|
|
k_mem_slab_alloc(&my_slab, &block_ptr, K_FOREVER);
|
|
... /* use memory block pointed at by block_ptr */
|
|
k_mem_slab_free(&my_slab, &block_ptr);
|
|
|
|
Suggested Uses
|
|
**************
|
|
|
|
Use a memory slab to allocate and free memory in fixed-size blocks.
|
|
|
|
Use memory slab blocks when sending large amounts of data from one thread
|
|
to another, to avoid unnecessary copying of the data.
|
|
|
|
Configuration Options
|
|
*********************
|
|
|
|
Related configuration options:
|
|
|
|
* None.
|
|
|
|
APIs
|
|
****
|
|
|
|
The following memory slab APIs are provided by :file:`kernel.h`:
|
|
|
|
* :c:macro:`K_MEM_SLAB_DEFINE`
|
|
* :cpp:func:`k_mem_slab_init()`
|
|
* :cpp:func:`k_mem_slab_alloc()`
|
|
* :cpp:func:`k_mem_slab_free()`
|
|
* :cpp:func:`k_mem_slab_num_used_get()`
|
|
* :cpp:func:`k_mem_slab_num_free_get()`
|