| .. _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()` |