blob: d3864944ff307eca5769664b9b645d39d15dbeb4 [file] [log] [blame]
.. _memory_maps_v2:
Memory Maps
###########
A :dfn:`memory map` is a kernel object that allows memory blocks
to be dynamically allocated from a designated memory region.
All memory blocks in a memory map 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 maps can be defined. Each memory map is referenced
by its memory address.
A memory map has the following key properties:
* The **block size** of each block, measured in bytes.
It must be at least 4 bytes long.
* The **number of blocks** available for allocation.
It must be greater than zero.
* A **buffer** that provides the memory for the memory map's blocks.
It must be at least "block size" times "number of blocks" bytes long.
A thread that needs to use a memory block simply allocates it from a memory
map. When the thread finishes with a memory block,
it must release the block back to the memory map 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 thread may wait on an empty memory map 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 map can be defined, if needed. This
allows for a memory map with smaller blocks and others with larger-sized
blocks. Alternatively, a memory pool object may be used.
Internal Operation
==================
A memory map's buffer is an array of fixed-size blocks,
with no wasted space between the blocks.
The memory map 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 Map
=====================
A memory map is defined using a variable of type :c:type:`struct k_mem_map`.
It must then be initialized by calling :cpp:func:`k_mem_map_init()`.
The following code defines and initializes a memory map that has 6 blocks
of 400 bytes each and is aligned to a 4-byte boundary..
.. code-block:: c
struct k_mem_map my_map;
char __aligned(4) my_map_buffer[6 * 400];
k_mem_map_init(&my_map, my_map_buffer, 400, 6);
Alternatively, a memory map can be defined and initialized at compile time
by calling :c:macro:`K_MEM_MAP_DEFINE()`.
The following code has the same effect as the code segment above. Observe
that the macro defines both the memory map and its buffer.
.. code-block:: c
K_MEM_MAP_DEFINE(my_map, 400, 6, 4);
Allocating a Memory Block
=========================
A memory block is allocated by calling :cpp:func:`k_mem_map_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_map_alloc(&my_map, &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_map_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_map_alloc(&my_map, &block_ptr, K_FOREVER);
... /* use memory block pointed at by block_ptr */
k_mem_map_free(&my_map, &block_ptr);
Suggested Uses
**************
Use a memory map to allocate and free memory in fixed-size blocks.
Use memory map 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 map APIs are provided by :file:`kernel.h`:
* :cpp:func:`k_mem_map_init()`
* :cpp:func:`k_mem_map_alloc()`
* :cpp:func:`k_mem_map_free()`
* :cpp:func:`k_mem_map_num_used_get()`
* :cpp:func:`k_mem_map_num_free_get()`