Back to libsm overview

# libsm : Resource Pools

$Id: rpool.html,v 1.4 2000/12/07 17:33:09 dmoen Exp $

## Introduction

A resource pool is an object that owns a collection of objects that can be freed all at once.

Resource pools simplify storage management.

Resource pools also speed up memory management. For example, here are some memory allocation statistics from a run of ``sendmail -q`` that delivered 3 messages:

>          18	1	     82	12	     87	24	      7	42	      2	84
>        3046	2	     18	13	      6	25	     89	44	      2	88
>         728	3	     15	14	      2	26	     14	48	      1	91
>          31	4	      9	15	      3	27	    104	52	      3	92
>         103	5	    394	16	     80	28	      8	56	      2	96
>         125	6	     16	17	      1	31	      2	60	      1	100
>          45	7	     14	18	     59	32	     10	64	      9	108
>         130	8	      6	19	      1	33	      6	68	      3	135
>          40	9	    111	20	      7	34	      1	72	     10	140
>          37	10	      7	21	     54	36	     10	76
>          34	11	      4	22	     38	40	      5	80

The second number in each pair is the size of a memory block; the first number is the number of blocks of that size. We can see that sendmail allocates large numbers of 2 byte blocks. These memory blocks can be allocated and freed more quickly using resource pools, because:

- When you allocate a small block from a resource pool, the rpool implementation carves off a chunk of a large preallocated block, and hands you a pointer to it.
- When you free a resource pool, only a small number of large blocks need to be freed.

## Synopsis

    #include <sm/rpool.h>

    typedef void (*SM_RPOOL_RFREE_T)(void *rcontext);
    typedef struct sm_rpool SM_RPOOL_T;
    typedef ... SM_RPOOL_ATTACH_T;

    SM_RPOOL_T *
    sm_rpool_new_x(
    	SM_RPOOL_T *parent);

    void
    sm_rpool_free(
    	SM_RPOOL_T *rpool);

    void *
    sm_rpool_malloc_x(
    	SM_RPOOL_T *rpool,
    	size_t size);

    SM_RPOOL_ATTACH_T
    sm_rpool_attach_x(
    	SM_RPOOL_T *rpool,
    	SM_RPOOL_RFREE_T rfree,
    	void *rcontext);

    void
    sm_rpool_detach(
    	SM_RPOOL_ATTACH_T);

    void
    sm_rpool_setsizes(
    	SM_RPOOL_T *rpool,
    	size_t poolsize,
    	size_t bigobjectsize);

## Description

`SM_RPOOL_T *sm_rpool_new_x(SM_RPOOL_T *parent)`
  Create a new resource pool object. Raise an exception if there is insufficient heap space. Initially, no memory is allocated for memory pools or resource lists.

  If parent != NULL then the new rpool will be added as a resource to the specified parent rpool, so that when the parent is freed, the child is also freed. However, even if a parent is specified, you can free the rpool at any time, and it will be automatically disconnected from the parent.

`void *sm_rpool_malloc_x(SM_RPOOL_T *rpool, size_t size)`
  Allocate a block of memory from a memory pool owned by the rpool. Raise an exception if there is insufficient heap space. A series of small allocation requests can be satisfied allocating them from the same memory pool, which reduces the number of calls to malloc. All of the memory allocated by sm_rpool_malloc_x is freed when the rpool is freed, and not before then.

`void sm_rpool_setsizes(SM_RPOOL_T *rpool, size_t poolsize, size_t bigobjectsize)`
  Set memory pool parameters. You can safely call this function at any time, but an especially good time to call it is immediately after creating the rpool, before any pooled objects have been allocated using sm_rpool_malloc_x.

  `poolsize` is the number of bytes of pool memory that will be available in the next pool object to be allocated. If you happen to know the total number of bytes of memory that you will allocate from an rpool using sm_rpool_malloc_x (including alignment padding), then you can pass that value as the poolsize, and only a single pool will be allocated during the lifetime of the rpool. `poolsize` is an optimization, not a hard limit: if you allocate more than this number of bytes from the rpool, then more than one memory pool may be allocated by the rpool to satisfy your requests.

  `bigobjectsize` is a value <= `poolsize`. It is used when an `sm_rpool_malloc_x` request exceeds the number of bytes available in the current pool. If the request is > `bigobjectsize` then the request will be satisfied by allocating a new block just for this specific request, and the current pool is not affected. If the request is <= `bigobjectsize` then the current pool is closed and a new memory pool is allocated, from which the request is satisfied. Consequently, no more than `bigobjectsize-1` bytes will ever be wasted at the end of a given pool.

  If poolsize or bigobjectsize are 0, then suitable default values are chosen.

`SM_RPOOL_ATTACH_T sm_rpool_attach_x(SM_RPOOL_T *rpool, SM_RPOOL_RFREE_T rfree, void *rcontext)`
  Attach an object to a resource pool, along with its free function. When the rpool is freed, the specified object will also be freed. Raise an exception if there is insufficient heap space.

  The return value is a magic cookie which, if passed to sm_rpool_detach, disconnects the object from the resource pool, which prevents the object's free function from being called when the rpool is freed.

`void sm_rpool_detach(SM_RPOOL_ATTACH_T a)`
  The argument is a magic cookie returned by `sm_rpool_attach_t`, and refers to the object that was attached to an rpool by a specific call to `sm_rpool_attach_t`. Disconnect the object from the resource pool, which prevents the object's free function from being called when the rpool is freed.

`void sm_rpool_free(SM_RPOOL_T *rpool)`
  Free an rpool object. All memory allocated using sm_rpool_malloc_x and all objects attached using sm_rpool_attach_x are freed at this time. If the rpool has a parent rpool, it is detached from its parent.