duanjigang 发表于 2010-01-11 22:30

发个简单(易用)的内存池

本帖最后由 duanjigang 于 2010-06-01 10:45 编辑


修改历史:
2010-02-01:
首先是把节点中的list和ptr改成 head 和tail了,为了方便理解,老炮给的意见
另外是,在节点中添加了一个raw_data指针,跟data在初始化时同时指向数据内存地址,这样做的目的是防止
用户在退出时忘记了free每一个node,如果采用以前的方式,整个内存池也就忘记Free了,虽然能够在退出时提示开发者,
修改后,能够在提示开发者的基础上释放未被释放的节点。
2010-06-01;
修改内容:其一,初始化N个节点时,为了保留栈的地址,须预留一个节点,因此最多只能申请到N-1个,做了修改,我们在实际开辟时申请N+1个,这样对用户就透明了。其二:new_mem_node时。需要把当前栈顶的节点的data置空,当时写错了,搞成了栈底节点的data置空,虽然不影响功能,但逻辑错误,做了修改。



######################################################################
简单技术含量不高还敢说,易用就看各位的反响了:em15: ,期待更好的改进建议。
自己根据实际工作需要写的,主要是为了省事,稍微提高点效率,省下了N多数组的声明和调用。
把多个类型的内存节点集合到一起统一管理,初始化时统一初始化,调用如下:init_mem_list (TYPE_S1, sizeof(s1_t), 100);
init_mem_list (TYPE_S2, sizeof(s2_t), 200);退出时统一释放,调用如下:clean_mem_list();运行过程中调用
调用封装的new和free函数extern u_int8_t * new_mem_node(u_int8_t type);
extern void free_mem_node( u_int8_t * addr);个人感觉还是比较方便的,效率相对还比较高,首先根据类型哈希到对应的链表上,然后每个链表就是一个栈,弹栈或者压栈就是new和Free操作。

一个简单的使用例子如下:

//cme_hook.c

#include <linux/module.h>
#include <linux/kernel.h>
#include "head.h"
#include "mem_pool.c"

typedef struct
{
    u_int16_t key1;
    u_int32_t key2;
}s1_t;
typedef struct
{
    u_int8_t key1;
    u_int16_t key2;
}s2_t;
const u_int8_t TYPE_S1 = 1;
const u_int8_t TYPE_S2 = 2;


s1_t* s1_list[20];
s2_t* s2_list[50];

int init(void)
{
    int i = 0;
    init_mem_list (TYPE_S1, sizeof(s1_t), 100);
    init_mem_list (TYPE_S2, sizeof(s2_t), 200);
   
    for (i = 0; i < 20; i++)
    {
      s1_list[i] = (s1_t*)new_mem_node(TYPE_S1);
      s1_list[i]->key1 = 2*i;
      s1_list[i]->key2 = 2*i+1;
    }
   
    for (i = 0; i < 50; i++)
    {
      s2_list[i] = (s2_t*)new_mem_node(TYPE_S2);
      s2_list[i]->key1 = 3*i;
      s2_list[i]->key2 = 3*i+1;
    }
   
    for (i = 0; i < 20; i++)
    {
      printk("s1_list[%d]=<%u, %u>\n", i, s1_list[i]->key1, s1_list[i]->key2);
    }

    for (i = 0; i < 50; i++)
    {
      printk("s2_list[%d]=<%u, %u>\n", i, s2_list[i]->key1, s2_list[i]->key2);
    }

   printk("cme hook registering.......\n");
   return 0;
}

void finish(void)
{
    int i = 0;

    for (i = 0; i < 20; i++) free_mem_node(((u_int8_t*)s1_list[i]));
    for (i = 0; i < 50; i++) free_mem_node(((u_int8_t*)s2_list[i]));
    clean_mem_list();
   printk("removing cme hook.......\n");
}

module_init(init)
module_exit(finish)
MODULE_LICENSE("GPL");
MODULE_VERSION("1.0");




附件是例子完整代码以及这个小小内存池的实现代码,大家多多提意见改进。:em02:
#######################################
附件看不到,贴下mem_pool.c中的实现代码

//mem_pool.c
#include <linux/module.h>
#include <linux/kernel.h>
#include "head.h"
int print_msg = 0;

#define MAX_MEM_LIST 256
typedef struct _node
{
    u_int8_t * data;
    struct _node * next;
    struct _node * pre;
}mem_node_t;
typedef struct
{
    mem_node_t * list;
    mem_node_t * ptr;   
    spinlock_t   lock;
    u_int8_t   type;
    u_int8_t   valid;
}mem_list_t;
static mem_list_t mem_list[MAX_MEM_LIST];
static int init_all_mem_list(void)
{
    int i = 0;
   
    for (i = 0; i < MAX_MEM_LIST; i++)
    {
      mem_list[i].list = NULL;
      mem_list[i].ptr = NULL;
      mem_list[i].type = 0;
      mem_list[i].valid = 0;
    }
    return 1;
}
static int mem_list_init = 0;
u_int8_t * new_mem_node(u_int8_t type)
{
    u_int8_t * prt = NULL;
    mem_node_t * plist = mem_list[type].list;
    if(!plist) return NULL;

    spin_lock(&mem_list[type].lock);   

    if(mem_list[type].ptr != mem_list[type].list)
    {
      prt = (u_int8_t*)(mem_list[type].ptr->data + 1);
      if(print_msg) printk("alloc one node:%p\n", prt);
      plist->data = NULL;
      mem_list[type].ptr = mem_list[type].ptr->pre;      
    }else
    {
      
      if(print_msg) printk("no node for alloc\n");
    }
    spin_unlock(&mem_list[type].lock);   
    return prt;
}
void free_mem_node( u_int8_t * addr)
{

    u_int8_t type = *(addr - 1);
    mem_list_t * plist = &mem_list[type];
   
    spin_lock(&plist->lock);   
   
    if(plist->ptr->next && addr)
    {
      if(print_msg) printk("free one mem node %p of type:%u\n", addr, type);
      plist->ptr = plist->ptr->next;
      plist->ptr->data = (u_int8_t*)(addr-1);   
    }else
    {
      if(print_msg) printk("freenode error\n");
    }   
    spin_unlock(&plist->lock);   
   
}

int init_mem_list ( u_int8_t type, int size, int length)
{
    int i = 0;
    mem_list_t * plist = &mem_list[i];

    if (!mem_list_init)
    {
      init_all_mem_list();
      mem_list_init = 1;
    }
   
    if ((type == 0)||(size <= 0) || (length <= 0)) return 0;
   
    plist = &mem_list[type];
   
    if(plist->valid) return 1;   
    plist->valid = 1;   
    spin_lock_init(&plist->lock);
    plist->type = type;

    for ( i = 0; i < length; i++ )
    {
      u_int8_t * ptype = 0;
      mem_node_t * p = (mem_node_t*)malloc(sizeof(mem_node_t));

      if(!p)goto err;
      
      p->data = malloc(size + sizeof(u_int8_t));
      
      if(!p->data)
      {
            free(p);
            goto err;
      }
      ptype = p->data;
      *ptype = type;
      //p->type = type;

      p->next = NULL;
      p->pre = NULL;
      if(!plist->list)
      {
            plist->list = p;
            plist->ptr = p;
            continue;
      }

      p->next = plist->list->next;
      plist->list->next = p;
      p->pre = plist->list;
      if(p->next) p->next->pre = p;
    }   
    while(plist->ptr->next) plist->ptr = plist->ptr->next;
    plist->valid = 1;
    if(print_msg) printk("init %dnodes of type %u success\n", length, type);
    return 1;
err:
    while(plist->list)
    {
      mem_node_t * p = plist->list;
      plist->list = plist->list->next;
      if(p)
      {
            if(p->data) free(p->data);
            free(p);
      }
    }
    mem_list[type].valid = 0;
    mem_list[type].type = 0;
    mem_list[type].list = NULL;
    mem_list[type].ptr = NULL;
    return 0;
}

void clean_mem_list(void)
{
   
    int num = 0;
    int left = -1;
    int i = 0;
    u_int8_t type;

    for (i = 0; i < MAX_MEM_LIST; i++)
    {
      mem_list_t * plist = &mem_list[i];
      if ( !plist->valid ) continue;
      plist->valid = 0;      
      type = plist->type;
      num = 0;   
      while(plist->list)
      {
            mem_node_t * p = plist->list;
            if(p == plist->ptr) left = 0;

            plist->list = plist->list->next;
            if(p)
            {
                num++;
                if(left >= 0) left++;
                if(p->data) free(p->data);
                free(p);
            }
      }
      
      if(print_msg)
      printk("free %d mem node(s) of type %u success, %d node(s) being used now\n",
            num, type, left - 1);
    }
}





头文件head.h

#ifndef _HEAD_H_
#define _HEAD_H_

#ifdef __KERNEL__
#define malloc(a) kmalloc(a,GFP_ATOMIC)
#define free(a) kfree(a)
#endif
extern u_int8_t * new_mem_node(u_int8_t type);
extern void free_mem_node( u_int8_t * addr);
extern int init_mem_list ( u_int8_t type, int size, int length);
extern void clean_mem_list(void);
#endif


目前没有在运行过程中做动态的reallocate,也就是说new失败时,就需要淘汰已有节点,主动free了

整个的存储图示意图如下:
[ 本帖最后由 duanjigang 于 2010-1-13 10:55 编辑 ]

duanjigang 发表于 2010-01-11 22:40

free做了个统一接口,因为类型存在了数据的前一个位置

Godbach 发表于 2010-01-11 22:42

多谢段兄的好文啊。现在好像看不了附件

duanjigang 发表于 2010-01-11 23:18

原帖由 Godbach 于 2010-1-11 22:42 发表 http://linux.chinaunix.net/bbs/images/common/back.gif
多谢段兄的好文啊。现在好像看不了附件
附件正在审核,奇怪了,再来一次看看

platinum 发表于 2010-01-11 23:23

最近严打呢好像

ubuntuer 发表于 2010-01-11 23:33

我看到的附件都是审核中谢谢分享
不过我记得好像sourceforge有个不错的内存池的^_^

scutan 发表于 2010-01-12 00:04

最近附件有点问题,好像是这周末能恢复。

duanjigang 发表于 2010-01-12 09:44

附件中的实现文件贴出来了

platinum 发表于 2010-01-12 09:49

借这个贴子问一下
段兄为何使用 spin_lock 而不是 spin_lock_bh,什么情况下应该加 _bh 什么时候应该不加呢?

Godbach 发表于 2010-01-12 10:07

原帖由 platinum 于 2010-1-12 09:49 发表 http://linux.chinaunix.net/bbs/images/common/back.gif
借这个贴子问一下
段兄为何使用 spin_lock 而不是 spin_lock_bh,什么情况下应该加 _bh 什么时候应该不加呢?

呵呵,白金兄这个问题还没有解决啊。
页: [1] 2 3 4 5
查看完整版本: 发个简单(易用)的内存池