首先是把节点中的list和ptr改成 head 和tail了,为了方便理解,老炮给的意见
另外是,在节点中添加了一个raw_data指针,跟data在初始化时同时指向数据内存地址,这样做的目的是防止
用户在退出时忘记了free每一个node,如果采用以前的方式,整个内存池也就忘记Free了,虽然能够在退出时提示开发者,
修改后,能够在提示开发者的基础上释放未被释放的节点。
2010-06-01;
修改内容:其一,初始化N个节点时,为了保留栈的地址,须预留一个节点,因此最多只能申请到N-1个,做了修改,我们在实际开辟时申请N+1个,这样对用户就透明了。其二:new_mem_node时。需要把当前栈顶的节点的data置空,当时写错了,搞成了栈底节点的data置空,虽然不影响功能,但逻辑错误,做了修改。
######################################################################
简单技术含量不高还敢说,易用就看各位的反响了 ,期待更好的改进建议。
自己根据实际工作需要写的,主要是为了省事,稍微提高点效率,省下了N多数组的声明和调用。
把多个类型的内存节点集合到一起统一管理,初始化时统一初始化,调用如下:
- init_mem_list (TYPE_S1, sizeof(s1_t), 100);
- init_mem_list (TYPE_S2, sizeof(s2_t), 200);
复制代码退出时统一释放,调用如下:
运行过程中调用
调用封装的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");
|
//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("free node 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 %d nodes 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了
整个的存储图示意图如下:

文章来源CU社区:发个简单(易用)的内存池
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69946831/viewspace-3159038/
,如需转载,请注明出处,否则将追究法律责任。