2015-07-14 16:26:06 -05:00
|
|
|
.. _memory_pools:
|
|
|
|
|
2015-08-07 13:35:41 -05:00
|
|
|
Memory Pools
|
|
|
|
############
|
2015-07-14 16:26:06 -05:00
|
|
|
|
|
|
|
Concepts
|
2015-08-07 13:35:41 -05:00
|
|
|
********
|
2015-07-14 16:26:06 -05:00
|
|
|
|
|
|
|
The microkernel's memory pool objects provide dynamic allocation and
|
|
|
|
release of variable-size memory blocks.
|
|
|
|
|
|
|
|
Unlike a memory map, which only supports memory blocks of a single size,
|
|
|
|
a memory pool has the ability to support multiple memory block sizes.
|
|
|
|
It does this by subdividing blocks into smaller chunks whenever possible
|
|
|
|
to more closely match the actual needs of the requesting task.
|
|
|
|
|
|
|
|
Any number of memory pools can be defined in a microkernel system.
|
|
|
|
Each memory pool has a name that uniquely identifies it.
|
|
|
|
In addition, a memory pool defines minimum and maximum memory block sizes
|
|
|
|
(in bytes) and the number of maximum size blocks that the memory pool
|
|
|
|
contains.
|
|
|
|
|
|
|
|
A task that needs to use a memory block simply allocates it from a
|
|
|
|
memory pool. If a block of the desired size is unavailable, the task
|
|
|
|
may choose to 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 may 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
|
|
|
|
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 file) is reached.
|
|
|
|
If the memory pool is unable to find an available block
|
|
|
|
that is at least the requested size, it will attempt to create
|
|
|
|
one by merging adjacent free blocks; if it is unable to create
|
|
|
|
a suitable block the request fails.
|
|
|
|
|
|
|
|
Although a memory pool uses efficient algorithms to manage its
|
|
|
|
blocks, splitting available blocks and merging free blocks
|
|
|
|
takes time and increases the overhead involved in allocating
|
|
|
|
a block. The larger the allowable number of splits, the larger
|
|
|
|
the overhead. 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 so that one application does not
|
|
|
|
allocate all of the available blocks.
|
|
|
|
|
|
|
|
|
|
|
|
Purpose
|
2015-08-07 13:35:41 -05:00
|
|
|
*******
|
2015-07-14 16:26:06 -05:00
|
|
|
Use memory pools to allocate memory in variable-size blocks.
|
|
|
|
|
|
|
|
Use memory pool blocks when sending data to a mailbox
|
|
|
|
asynchronously.
|
|
|
|
|
|
|
|
|
|
|
|
Usage
|
2015-08-07 13:35:41 -05:00
|
|
|
*****
|
2015-07-14 16:26:06 -05:00
|
|
|
|
|
|
|
Defining a Memory Pool
|
2015-08-07 13:35:41 -05:00
|
|
|
======================
|
2015-07-14 16:26:06 -05:00
|
|
|
|
|
|
|
The following parameters must be defined:
|
|
|
|
|
|
|
|
*name*
|
|
|
|
This specifies a unique name for the memory pool.
|
|
|
|
|
2015-08-18 16:15:10 -04:00
|
|
|
*min_block_size*
|
2015-07-14 16:26:06 -05:00
|
|
|
This specifies the minimimum memory block size in bytes.
|
|
|
|
It should be a multiple of the processor's word size.
|
|
|
|
|
2015-08-18 16:15:10 -04:00
|
|
|
*max_block_size*
|
2015-07-14 16:26:06 -05:00
|
|
|
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.
|
|
|
|
|
2015-08-18 16:15:10 -04:00
|
|
|
*num_max*
|
2015-07-14 16:26:06 -05:00
|
|
|
This specifies the number of maximum size memory blocks
|
|
|
|
available at startup.
|
|
|
|
|
|
|
|
|
2015-08-18 16:15:10 -04:00
|
|
|
Public Memory Pool
|
|
|
|
------------------
|
|
|
|
|
|
|
|
Define the memory pool in the application's .MDEF file using the following
|
|
|
|
syntax:
|
2015-07-14 16:26:06 -05:00
|
|
|
|
|
|
|
.. code-block:: console
|
|
|
|
|
2015-08-18 16:15:10 -04:00
|
|
|
POOL name min_block_size max_block_size num_max
|
2015-07-14 16:26:06 -05:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2015-09-01 12:39:22 -04:00
|
|
|
A public memory pool can be referenced by name from any source file that
|
|
|
|
includes the file :file:`zephyr.h`.
|
2015-08-18 16:15:10 -04:00
|
|
|
|
|
|
|
.. note::
|
|
|
|
Private memory pools are not supported by the Zephyr kernel.
|
|
|
|
|
2015-07-14 16:26:06 -05:00
|
|
|
|
|
|
|
Example: Requesting a Memory Block from a Pool with No Conditions
|
2015-08-07 13:35:41 -05:00
|
|
|
=================================================================
|
2015-07-14 16:26:06 -05:00
|
|
|
|
|
|
|
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_wait(&block, MYPOOL, 80);
|
|
|
|
|
|
|
|
memset(block.pointer_to_data, 0, 80);
|
|
|
|
|
|
|
|
|
|
|
|
Example: Requesting a Memory Block from a Pool with a Conditional Time-out
|
2015-08-07 13:35:41 -05:00
|
|
|
==========================================================================
|
|
|
|
|
2015-07-14 16:26:06 -05:00
|
|
|
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_wait_timeout(&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
|
2015-08-07 13:35:41 -05:00
|
|
|
===========================================================================
|
|
|
|
|
2015-07-14 16:26:06 -05:00
|
|
|
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) == RC_OK) {
|
|
|
|
/* use memory block */
|
|
|
|
} else {
|
|
|
|
printf('Memory allocation timeout');
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Example: Freeing a Memory Block Back to a Pool
|
2015-08-07 13:35:41 -05:00
|
|
|
==============================================
|
|
|
|
|
2015-07-14 16:26:06 -05:00
|
|
|
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);
|
|
|
|
/* use memory block */
|
|
|
|
task_mem_pool_free(&block);
|
|
|
|
|
|
|
|
|
|
|
|
Example: Manually Defragmenting a Memory Pool
|
2015-08-07 13:35:41 -05:00
|
|
|
=============================================
|
|
|
|
|
2015-07-14 16:26:06 -05:00
|
|
|
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 having to do an implicit partial defragmentation of the memory pool
|
|
|
|
each time a memory block allocation occurs.
|
|
|
|
|
|
|
|
.. code-block:: c
|
|
|
|
|
|
|
|
task_mem_pool_defragment(MYPOOL);
|
|
|
|
|
|
|
|
APIs
|
2015-08-07 13:35:41 -05:00
|
|
|
****
|
2015-07-14 16:26:06 -05:00
|
|
|
|
|
|
|
The following Memory Pools APIs are provided by microkernel.h.
|
|
|
|
|
|
|
|
+----------------------------------------------+------------------------------+
|
|
|
|
| Call | Description |
|
|
|
|
+==============================================+==============================+
|
|
|
|
| :c:func:`task_mem_pool_alloc()` | Allocates a block from |
|
|
|
|
| | a memory pool. |
|
|
|
|
+----------------------------------------------+------------------------------+
|
|
|
|
| :c:func:`task_mem_pool_alloc_wait()` | Waits for a block of memory |
|
|
|
|
| | until it is available. |
|
|
|
|
+----------------------------------------------+------------------------------+
|
|
|
|
| :c:func:`task_mem_pool_alloc_wait_timeout()` | Waits for a block of memory |
|
|
|
|
| | for the time period defined |
|
|
|
|
| | by the time-out parameter. |
|
|
|
|
+----------------------------------------------+------------------------------+
|
|
|
|
| :c:func:`task_mem_pool_free()` | Returns a block of memory |
|
|
|
|
| | to a memory pool. |
|
|
|
|
+----------------------------------------------+------------------------------+
|
|
|
|
| :c:func:`task_mem_pool_defragment()` | Defragments a memory pool. |
|
|
|
|
+----------------------------------------------+------------------------------+
|