zephyr/doc/kernel/microkernel/microkernel_memory_pools.rst

204 lines
6.5 KiB
ReStructuredText

.. _microkernel_memory_pools:
Memory Pools
############
Concepts
********
The microkernel's :dfn:`memory pool` objects provide dynamic allocation and
release of variable-size memory blocks.
Unlike :ref:`memory map <microkernel_memory_map>` objects, which support
memory blocks of only a *single* size, a memory pool can support memory blocks
of *various* sizes. The memory pool does this by subdividing blocks into smaller
chunks, where possible, to more closely match the actual needs of a requesting
task.
Any number of memory pools can be defined in a microkernel system. Each memory
pool has:
* A **name** that uniquely identifies it.
* A **minimum** and **maximum** block size, in bytes, of memory blocks
within the pool.
* The **number of maximum-size memory blocks** initially available.
A task that needs to use a memory block simply allocates it from a memory
pool. When a block of the desired size is unavailable, the task can wait
for one to become available. Following a successful allocation, the
:c:data:`pointer_to_data` field of the block descriptor supplied by the
task indicates the starting address of the memory block. When the task is
finished with a memory block, it must release the block back to the memory
pool that allocated it so that the block can be reused.
Any number of tasks can wait on a memory pool simultaneously; when a
memory block becomes available, it is given to the highest-priority task
that has waited the longest.
When a request for memory is sufficiently smaller than an available
memory pool block, the memory pool will automatically split the block into
4 smaller blocks. The resulting smaller blocks can also be split repeatedly,
until a block just larger than the needed size is available, or the minimum
block size, as specified in the MDEF, is reached.
If the memory pool cannot find an available block that is at least
the requested size, it will attempt to create one by merging adjacent
free blocks. If a suitable block can't be created, the request fails.
Although a memory pool uses efficient algorithms to manage its blocks,
the splitting of available blocks and merging of free blocks takes time
and increases overhead block allocation. The larger the allowable
number of splits, the larger the overhead. However, the minimum and maximum
block-size parameters specified for a pool can be used to control the amount
of splitting, and thus the amount of overhead.
Unlike a heap, more than one memory pool can be defined, if needed. For
example, different applications can utilize different memory pools; this
can help prevent one application from hijacking resources to allocate all
of the available blocks.
Purpose
*******
Use memory pools to allocate memory in variable-size blocks.
Use memory pool blocks when sending data to a mailbox asynchronously.
Usage
*****
Defining a Memory Pool
======================
The following parameters must be defined:
*name*
This specifies a unique name for the memory pool.
*min_block_size*
This specifies the minimum memory block size in bytes.
It should be a multiple of the processor's word size.
*max_block_size*
This specifies the maximum memory block size in bytes.
It should be a power of 4 times larger than *minBlockSize*;
therefore, maxBlockSize = minBlockSize * 4^n, where n>=0.
*num_max*
This specifies the number of maximum size memory blocks
available at startup.
Public Memory Pool
------------------
Define the memory pool in the application's MDEF with the following
syntax:
.. code-block:: console
POOL name min_block_size max_block_size num_max
For example, the file :file:`projName.mdef` defines two memory pools
as follows:
.. code-block:: console
% POOL NAME MIN MAX NMAX
% =======================================
POOL MY_POOL 32 8192 1
POOL SECOND_POOL_ID 64 1024 5
A public memory pool can be referenced by name from any source file that
includes the file :file:`zephyr.h`.
.. note::
Private memory pools are not supported by the Zephyr kernel.
Example: Requesting a Memory Block from a Pool with No Conditions
=================================================================
This code waits indefinitely for an 80 byte memory block to become
available, then fills it with zeroes.
.. code-block:: c
struct k_block block;
task_mem_pool_alloc(&block, MYPOOL, 80, TICKS_UNLIMITED);
memset(block.pointer_to_data, 0, 80);
Example: Requesting a Memory Block from a Pool with a Conditional Time-out
==========================================================================
This code waits up to 5 ticks for an 80 byte memory block to become
available and gives a warning if a suitable memory block is not obtained
in that time.
.. code-block:: c
struct k_block block;
if (task_mem_pool_alloc(&block, MYPOOL, 80, 5) == RC_OK) {
/* use memory block */
} else {
printf('Memory allocation timeout');
}
Example: Requesting a Memory Block from a Pool with a No-Blocking Condition
===========================================================================
This code gives an immediate warning when it can not satisfy the request for
a memory block of 80 bytes.
.. code-block:: c
struct k_block block;
if (task_mem_pool_alloc (&block, MYPOOL, 80, TICKS_NONE) == RC_OK) {
/* use memory block */
} else {
printf('Memory allocation timeout');
}
Example: Freeing a Memory Block Back to a Pool
==============================================
This code releases a memory block back to a pool when it is no longer needed.
.. code-block:: c
struct k_block block;
task_mem_pool_alloc(&block, MYPOOL, size, TICKS_NONE);
/* use memory block */
task_mem_pool_free(&block);
Example: Manually Defragmenting a Memory Pool
=============================================
This code instructs the memory pool to concatenate any unused memory blocks
that can be merged. Doing a full defragmentation of the entire memory pool
before allocating a number of memory blocks may be more efficient than doing
an implicit partial defragmentation of the memory pool each time a memory
block allocation occurs.
.. code-block:: c
task_mem_pool_defragment(MYPOOL);
APIs
****
Memory Pools APIs provided by :file:`microkernel.h`
===================================================
:cpp:func:`task_mem_pool_alloc()`
Wait for a block of memory; wait the period of time defined by the time-out
parameter.
:cpp:func:`task_mem_pool_free()`
Return a block of memory to a memory pool.
:cpp:func:`task_mem_pool_defragment()`
Defragment a memory pool.