diff --git a/src/lib/mempool-allocfree.c b/src/lib/mempool-allocfree.c index 2019ecb410..f4af17627f 100644 --- a/src/lib/mempool-allocfree.c +++ b/src/lib/mempool-allocfree.c @@ -6,6 +6,88 @@ #include "mempool.h" #include "llist.h" +/* + * As the name implies, allocfree pools support both allocating and freeing + * memory. + * + * Implementation + * ============== + * + * Each allocfree pool contains a pool structure (struct allocfree_pool) to + * keep track of allocfree-specific pool information and zero or more blocks + * (struct pool_block) that keep track of ranges of memory used to back the + * allocations. The blocks are kept in a doubly-linked list used to keep + * track of all allocations that belong to the pool. + * + * +-----------+ + * | allocfree | + * | pool | + * +-----+-----+ + * | + * | blocks +------------+ next +------------+ next + * \------->| pool block |<=====>| pool block |<=====>...<====> NULL + * +------------+ prev +------------+ prev + * | | | | + * . . + * . . + * . | | + * . +------------+ + * | | + * +------------+ + * + * Creation + * -------- + * + * When an allocfree pool is created the linked list of allocated blocks is + * initialized to be empty. + * + * Allocation & Freeing + * -------------------- + * + * Since each allocation (via p_malloc()) corresponds to one block, + * allocations are simply a matter of: + * + * - allocating enough memory from the system heap (via calloc()) to hold + * the block header and the requested number of bytes, + * - making a note of the user-requested size in the block header, + * - adding the new block to the pool's linked list of blocks, and + * - returning a pointer to the payload area of the block to the caller. + * + * Freeing memory is simpler. The passed in pointer is converted to a + * struct pool_block pointer. Then the block is removed from the pool's + * linked list and free()d. + * + * If the pool was created via pool_allocfree_create_clean(), all blocks are + * safe_memset() to zero just before being free()d. + * + * Reallocation + * ------------ + * + * Reallocation is done by calling realloc() with a new size that is large + * enough to cover the requested number of bytes plus the block header + * overhead. + * + * Clearing + * -------- + * + * Clearing the pool is supposed to return the pool to the same state it was + * in when it was first created. To that end, the allocfree pool frees all + * the blocks allocated since the pool's creation. In other words, clearing + * is equivalent to (but faster than) calling p_free() for each allocation + * in the pool. + * + * Finally, if the pool was created via pool_allocfree_create_clean(), all + * blocks are safe_memset() to zero before being free()d. + * + * Destruction + * ----------- + * + * Destroying a pool first clears it (see above) and then the pool structure + * itself is safe_memset() to zero (if pool_allocfree_create_clean() was + * used) and free()d. (The clearing leaves the pool in a minimal state + * with no blocks allocated.) + */ + #define MAX_ALLOC_SIZE SSIZE_T_MAX struct allocfree_pool {