snort 内存池源码实现分析

源码mempool.h|c  sf_sdlist_types.h

内存池涉及几个动作 :初始化、分配、释放、销毁、清空

底层使用两个链表实现内存的分配used_list与释放回收free_list

int mempool_init(MemPool *mempool, PoolCount num_objects, size_t obj_size);
int mempool_destroy(MemPool *mempool);
MemBucket *mempool_alloc(MemPool *mempool);
void mempool_free(MemPool *mempool, MemBucket *obj);
int mempool_clean(MemPool *mempool);

数据结构

typedef unsigned int PoolCount;

typedef struct _MemBucket
{
    /* 链表元素节点*/
    SDListItem *key;
    int used;
    /* 用于存储datapool中单个元素的指针*/
    void *data;
} MemBucket;


typedef struct _MemPool
{
    /* 分配的连续内存空间*/
    void **datapool; /* memory buffer for MemBucket->data */

    /* 桶数组  */
    MemBucket *bucketpool; /* memory buffer */
    /* 链表节点数组*/
    SDListItem *listpool; /* list of things to use for memory bufs */

    PoolCount total;

    /* 这两个链表使用sf_sdlist_append 将listpool、bucketpool、datapool结合起来*/
    /* 剩余多少*/
    sfSDList free_list;
    /* 使用多少 */
    sfSDList used_list;

    /* 元素大小*/
    size_t obj_size;
} MemPool;

snort的链表是一个双向链表,有时间在后面的博客会继续分析。


/* Function: int mempool_init(MemPool *mempool,
 *                            PoolCount num_objects, size_t obj_size)
 *
 * Purpose: initialize a mempool object and allocate memory for it
 * Args: mempool - pointer to a MemPool struct
 *       num_objects - number of items in this pool
 *       obj_size    - size of the items
 *
 * Returns: 0 on success, 1 on failure
 */

int mempool_init(MemPool *mempool, PoolCount num_objects, size_t obj_size)
{
    PoolCount i;

    if(mempool == NULL)
        return 1;

    if(num_objects < 1)
        return 1;

    if(obj_size < 1)
        return 1;

    /* 单个元素的大小*/
    mempool->obj_size = obj_size;

    /* this is the basis pool that represents all the *data pointers
       in the list */
    /* 分配一块连续的空间,供内存池进行分配操作*/
    mempool->datapool = calloc(num_objects, obj_size);
    if(mempool->datapool == NULL)
        return 1;

    /* 分配对应num_objects个链表节点, 为后面构建两个分配和回收链表使用*/
    mempool->listpool = calloc(num_objects, sizeof(SDListItem));
    if(mempool->listpool == NULL)
    {
        /* well, that sucked, lets clean up */
        ErrorMessage("%s(%d) mempool_init(): listpool is null\n",
                     __FILE__, __LINE__);
        mempool_free_pools(mempool);
        return 1;
    }

    /* 每一个元素使用MemBucket进行封装管理, 一样分配num_objects个*/
    mempool->bucketpool = calloc(num_objects, sizeof(MemBucket));
    if(mempool->bucketpool == NULL)
    {
        ErrorMessage("%s(%d) mempool_init(): bucketpool is null\n",
                     __FILE__, __LINE__);
        mempool_free_pools(mempool);
        return 1;
    }

    /* 初始化这两个内存管理链表*/
    /* sets up the 2 memory lists */
    if(sf_sdlist_init(&mempool->used_list, NULL))
    {
        ErrorMessage("%s(%d) mempool_init(): Failed to initialize used list\n",
                     __FILE__, __LINE__);
        mempool_free_pools(mempool);
        return 1;
    }

    if(sf_sdlist_init(&mempool->free_list, NULL))
    {
        ErrorMessage("%s(%d) mempool_init(): Failed to initialize free list\n",
                     __FILE__, __LINE__);
        mempool_free_pools(mempool);
        return 1;
    }


    /*  循环处理, 将被分割的内存使用bucket封装, 最后将bucket 放到链表节点SDListItem的data中加入到free_list的链表尾部*/
    for(i=0; i<num_objects; i++)
    {
        SDListItem *itemp;
        MemBucket *bp;

        bp = &mempool->bucketpool[i];
        itemp = &mempool->listpool[i];

        /* each bucket knows where it resides in the list */
        bp->key = itemp;

#ifdef TEST_MEMPOOL
        printf("listpool: %p itemp: %p diff: %u\n",
            mempool->listpool, itemp,
            (((char *) itemp) - ((char *) mempool->listpool)));
#endif
        /* 对连续内存进行切割使用*/
        bp->data = ((char *) mempool->datapool) + (i * mempool->obj_size);

#ifdef TEST_MEMPOOL
        printf("datapool: %p bp.data: %p diff: %u\n",
            mempool->datapool,
            mempool->datapool + (i * mempool->obj_size),
            (((char *) bp->data) - ((char *) mempool->datapool)));
#endif

        /* 添加到free_list的尾部*/
        if(sf_sdlist_append(&mempool->free_list,
                            &mempool->bucketpool[i],
                            &mempool->listpool[i]))
        {
            ErrorMessage("%s(%d) mempool_init(): Failed to add to free list\n",
                         __FILE__, __LINE__);
            mempool_free_pools(mempool);
            return 1;
        }

        mempool->total++;
    }

    return 0;
}

内存分配动作



/* Function: MemBucket *mempool_alloc(MemPool *mempool);
 *
 * Purpose: allocate a new object from the mempool
 * Args: mempool - pointer to a MemPool struct
 *
 * Returns: a pointer to the mempool object on success, NULL on failure
 */
MemBucket *mempool_alloc(MemPool *mempool)
{
    SDListItem *li = NULL;
    MemBucket *b;

    if(mempool == NULL)
    {
        return NULL;
    }

    /* get one item off the free_list,
       put one item on the usedlist
     */

    /* 从回收链表free_list中拿掉一个节点*/
    li = mempool->free_list.head;

    if((li == NULL) || sf_sdlist_remove(&mempool->free_list, li))
    {
#ifdef TEST_MEMPOOL
        printf("Failure on sf_sdlist_remove\n");
#endif
        return NULL;
    }

    /* 将从free_list中拿掉的节点加入used_list中, 进行管理,表明这个节点已使用*/
    if(sf_sdlist_append(&mempool->used_list, li->data, li))
    {
#ifdef TEST_MEMPOOL
        printf("Failure on sf_sdlist_append\n");
#endif
        return NULL;
    }

    /* 返回bucket指针, 将初始化的时候那块连续的内存的某一个对象的内存clean*/
    /* TBD -- make configurable */
    b = li->data;
    bzero(b->data, mempool->obj_size);

    return b;
}

内存回收动作:

/*
 * 将要释放的对象从used_list中删除,然后添加到free_list中
 */
void mempool_free(MemPool *mempool, MemBucket *obj)
{
    if ((mempool == NULL) || (obj == NULL))
        return;

    if(sf_sdlist_remove(&mempool->used_list, obj->key))
    {
#ifdef TEST_MEMPOOL
        printf("failure on remove from used_list");
#endif
        return;
    }

    /* put the address of the membucket back in the list */
    if(sf_sdlist_append(&mempool->free_list, obj, obj->key))
    {
#ifdef TEST_MEMPOOL
        printf("failure on add to free_list");
#endif
        return;
    }

    return;
}

内存的分配和释放,都是通过链表的插入删除,时间复杂度o(1)。由于snort使用的单进程单线程架构,不涉及到多线程操作,无需加锁。

猜你喜欢

转载自blog.csdn.net/guoguangwu/article/details/88378800
今日推荐