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).

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 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 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 os_membuf_t` elements required by the memory pool. The 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. OS_ALIGNMENT).

void *my_memory_buffer;
my_memory_buffer = malloc(OS_MEMPOOL_BYTES(NUM_BLOCKS, BLOCK_SIZE));
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 os_mempool_init`().

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 os_memblock_get(). When the memory block is no longer needed the memory can be freed by calling os_memblock_put().

API

typedef os_error_t os_mempool_put_fn(struct os_mempool_ext *ome, void *data, void *arg)

Block put callback function.

If configured, this callback gets executed whenever a block is freed to the corresponding extended mempool. Note: The os_memblock_put() function calls this callback instead of freeing the block itself. Therefore, it is the callback’s responsibility to free the block via a call to os_memblock_put_from_cb().

Return

Indicates whether the block was successfully freed. A non-zero value should only be returned if the block was not successfully released back to its pool.

Parameters
  • ome: The extended mempool that a block is being freed back to.

  • data: The block being freed.

  • arg: Optional argument configured along with the callback.

struct os_mempool *os_mempool_info_get_next(struct os_mempool *mp, struct os_mempool_info *omi)

Get information about the next system memory pool.

Return

The next memory pool in the list to get information about; NULL when at the last memory pool.

Parameters
  • mp: The current memory pool, or NULL if starting iteration.

  • omi: A pointer to the structure to return memory pool information into.

struct os_mempool *os_mempool_get(const char *mempool_name, struct os_mempool_info *info)

Get information system memory pool by name.

Return

The memory pool found; NULL when there is no such memory pool.

Parameters
  • mempool_name: The name of mempool.

  • info: A pointer to the structure to return memory pool information into, can be NULL.

os_error_t os_mempool_init(struct os_mempool *mp, uint16_t blocks, uint32_t block_size, void *membuf, char *name)

Initialize a memory pool.

Return

0 on success; Non-zero error code on failure.

Parameters
  • mp: Pointer to a pointer to a mempool

  • blocks: The number of blocks in the pool

  • block_size: The size of the block, in bytes.

  • membuf: Pointer to memory to contain blocks.

  • name: Name of the pool.

os_error_t os_mempool_ext_init(struct os_mempool_ext *mpe, uint16_t blocks, uint32_t block_size, void *membuf, char *name)

Initializes an extended memory pool.

Extended attributes (e.g., callbacks) are not specified when this function is called; they are assigned manually after initialization.

Return

0 on success; Non-zero error code on failure.

Parameters
  • mpe: The extended memory pool to initialize.

  • blocks: The number of blocks in the pool.

  • block_size: The size of each block, in bytes.

  • membuf: Pointer to memory to contain blocks.

  • name: Name of the pool.

os_error_t os_mempool_unregister(struct os_mempool *mp)

Removes the specified mempool from the list of initialized mempools.

Return

0 on success; OS_INVALID_PARM if the mempool is not registered.

Parameters
  • mp: The mempool to unregister.

os_error_t os_mempool_clear(struct os_mempool *mp)

Clears a memory pool.

Return

0 on success; Non-zero error code on failure.

Parameters
  • mp: The mempool to clear.

bool os_mempool_is_sane(const struct os_mempool *mp)

Performs an integrity check of the specified mempool.

This function attempts to detect memory corruption in the specified memory pool.

Return

true if the memory pool passes the integrity check; false if the memory pool is corrupt.

Parameters
  • mp: The mempool to check.

int os_memblock_from(const struct os_mempool *mp, const void *block_addr)

Checks if a memory block was allocated from the specified mempool.

Return

0 if the block does not belong to the mempool; 1 if the block does belong to the mempool.

Parameters
  • mp: The mempool to check as parent.

  • block_addr: The memory block to check as child.

void *os_memblock_get(struct os_mempool *mp)

Get a memory block from a memory pool.

Return

Pointer to block if available; NULL otherwise

Parameters
  • mp: Pointer to the memory pool

os_error_t os_memblock_put_from_cb(struct os_mempool *mp, void *block_addr)

Puts the memory block back into the pool, ignoring the put callback, if any.

This function should only be called from a put callback to free a block without causing infinite recursion.

Return

0 on success; Non-zero error code on failure.

Parameters
  • mp: Pointer to memory pool

  • block_addr: Pointer to memory block

os_error_t os_memblock_put(struct os_mempool *mp, void *block_addr)

Puts the memory block back into the pool.

Return

0 on success; Non-zero error code on failure.

Parameters
  • mp: Pointer to memory pool

  • block_addr: Pointer to memory block

OS_MEMPOOL_F_EXT

Indicates an extended mempool.

Address can be safely cast to (struct os_mempool_ext *).

OS_MEMPOOL_INFO_NAME_LEN

Length of the name of memory pool.

OS_MEMPOOL_BLOCK_SZ(sz)

Leave extra 4 bytes of guard area at the end.

OS_MEMPOOL_SIZE(n, blksize)

The total size of a memory pool, including alignment.

OS_MEMPOOL_BYTES(n, blksize)

Calculates the number of bytes required to initialize a memory pool.

struct os_memblock
#include <os_mempool.h>

A memory block structure.

This simply contains a pointer to the free list chain and is only used when the block is on the free list. When the block has been removed from the free list the entire memory block is usable by the caller.

Public Functions

SLIST_ENTRY (os_memblock) mb_next

Next memory block in the list.

struct os_mempool
#include <os_mempool.h>

Memory pool.

Public Functions

STAILQ_ENTRY (os_mempool) mp_list

Next memory pool in the list.

SLIST_HEAD (, os_memblock)

Head of the list of memory blocks.

Public Members

uint32_t mp_block_size

Size of the memory blocks, in bytes.

uint16_t mp_num_blocks

The number of memory blocks.

uint16_t mp_num_free

The number of free blocks left.

uint16_t mp_min_free

The lowest number of free blocks seen.

uint8_t mp_flags

Bitmap of OS_MEMPOOL_F_[…] values.

uintptr_t mp_membuf_addr

Address of memory buffer used by pool.

char *name

Name for memory block.

struct os_mempool_ext
#include <os_mempool.h>

Extended memory pool.

Public Members

struct os_mempool mpe_mp

Standard memory pool.

os_mempool_put_fn *mpe_put_cb

Callback that is executed immediately when a block is freed.

void *mpe_put_arg

Optional argument passed to the callback function.

struct os_mempool_info
#include <os_mempool.h>

Information describing a memory pool, used to return OS information to the management layer.

Public Members

int omi_block_size

Size of the memory blocks in the pool.

int omi_num_blocks

Number of memory blocks in the pool.

int omi_num_free

Number of free memory blocks.

int omi_min_free

Minimum number of free memory blocks ever.

char omi_name[OS_MEMPOOL_INFO_NAME_LEN]

Name of the memory pool.