204 lines
6.5 KiB
ReStructuredText
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.
|