Memory Pools
============

A memory pool is a collection of fixed sized elements called memory
blocks. Generally, memory pools are used when the developer wants to
allocate a certain amount of memory to a given feature. Unlike the heap,
where a code module is at the mercy of other code modules to insure
there is sufficient memory, memory pools can insure sufficient memory
allocation.

Description
------------

In order to create a memory pool the developer needs to do a few things.
The first task is to define the memory pool itself. This is a data
structure which contains information about the pool itself (i.e. number
of blocks, size of the blocks, etc).

.. code:: c

    struct os_mempool my_pool;

The next order of business is to allocate the memory used by the memory
pool. This memory can either be statically allocated (i.e. a global
variable) or dynamically allocated (i.e. from the heap). When
determining the amount of memory required for the memory pool, simply
multiplying the number of blocks by the size of each block is not
sufficient as the OS may have alignment requirements. The alignment size
definition is named :c:macro:`OS_ALIGNMENT` and can be found in os\_arch.h as
it is architecture specific. The memory block alignment is usually for
efficiency but may be due to other reasons. Generally, blocks are
aligned on 32-bit boundaries. Note that memory blocks must also be of
sufficient size to hold a list pointer as this is needed to chain memory
blocks on the free list.

In order to simplify this for the user two macros have been provided:
c:macro:`OS_MEMPOOL_BYTES(n, blksize)` and :c:macro:`OS_MEMPOOL_SIZE(n, blksize)`.
The first macro returns the number of bytes needed for the memory pool
while the second returns the number of :c:type:`os_membuf_t`` elements required
by the memory pool. The :c:type:`os_membuf_t` type is used to guarantee that
the memory buffer used by the memory pool is aligned on the correct
boundary.

Here are some examples. Note that if a custom malloc implementation is
used it must guarantee that the memory buffer used by the pool is
allocated on the correct boundary (i.e. :c:macro:`OS_ALIGNMENT`).

.. code:: c

    void *my_memory_buffer;
    my_memory_buffer = malloc(OS_MEMPOOL_BYTES(NUM_BLOCKS, BLOCK_SIZE));

.. code:: c

    os_membuf_t my_memory_buffer[OS_MEMPOOL_SIZE(NUM_BLOCKS, BLOCK_SIZE)];

Now that the memory pool has been defined as well as the memory
required for the memory blocks which make up the pool the user needs to
initialize the memory pool by calling :c:func:`os_mempool_init``.

.. code:: c

    os_mempool_init(&my_pool, NUM_BLOCKS, BLOCK_SIZE, my_memory_buffer,
                             "MyPool");

Once the memory pool has been initialized the developer can allocate
memory blocks from the pool by calling :c:func:`os_memblock_get`. When the
memory block is no longer needed the memory can be freed by calling
:c:func:`os_memblock_put`.

API
-----

.. doxygengroup:: OSMempool
    :content-only:
    :members:


