转自:http://blog.chinaunix.net/uid-28458801-id-4254501.html
操作系统:ubuntu10.04
前言:
在通信过程中,无法知道将会接收到的数据的长度,因此开一个固定大小的缓冲区并不合适,开大了,很可能大多数通信都只是几十个自己而已;开小了,又无法处理大数据。因此最好的方法就是创建内存池,根据实际情况,分配合适大小的内存空间。
一,思路
通过双向链表,管理所有的内存池。
二,实现
1,内存池的相关信息结构体
点击(此处)折叠或打开
-
struct pool_head {
-
void **free_list;
-
struct list_head list; /* list of all known pools */
-
int32_t used; /* how many chunks are currently in use */
-
int32_t allocated; /* how many chunks have been allocated */
-
int32_t limit; /* hard limit on the number of chunks */
-
int32_t minavail; /* how many chunks are expected to be used */
-
int32_t size; /* chunk size */
-
int32_t flags; /* MEM_F_* */
-
int32_t users; /* number of pools sharing this zone */
-
int8_t name[12]; /* name of the pool */
- };
2,具体实现
a,头文件(pools.h)
点击(此处)折叠或打开
-
#ifndef __POOLS_H__
-
#define __POOLS_H__
-
-
#ifdef __cplusplus
-
extern "C" {
-
#endif
-
-
/* Define to prevent recursive inclusion
-
-------------------------------------*/
-
#include "types.h"
-
#include "list.h"
-
-
-
#define MEM_F_SHARED 0x1 /* 标示对应的池允许共用 */
-
-
-
/* 每个池的相关信息 */
-
struct pool_head {
-
void **free_list;
-
struct list_head list; /* list of all known pools */
-
int32_t used; /* how many chunks are currently in use */
-
int32_t allocated; /* how many chunks have been allocated */
-
int32_t limit; /* hard limit on the number of chunks */
-
int32_t minavail; /* how many chunks are expected to be used */
-
int32_t size; /* chunk size */
-
int32_t flags; /* MEM_F_* */
-
int32_t users; /* number of pools sharing this zone */
-
int8_t name[12]; /* name of the pool */
-
};
-
-
-
/* 池创建 */
-
/* Try to find an existing shared pool with the same characteristics and
-
* returns it, otherwise creates this one. NULL is returned if no memory
-
* is available for a new creation.
-
*/
-
extern struct pool_head * pool_create(char *name, uint32_t size, uint32_t flags);
-
-
-
/* 池销毁 */
-
/*
-
* This function destroys a pool by freeing it completely, unless it's still
-
* in use. This should be called only under extreme circumstances. It always
-
* returns NULL if the resulting pool is empty, easing the clearing of the old
-
* pointer, otherwise it returns the pool.
-
* .
-
*/
-
extern void* pool_destroy(struct pool_head *pool);
-
-
-
/* 把池中的空闲的元素都给释放掉 */
-
/*
-
* This function frees whatever can be freed in pool <pool>.
-
*/
-
extern void pool_clear(struct pool_head *pool);
-
-
-
/* 把池中非必要的元素给释放掉 */
-
/*
-
* This function frees whatever can be freed in all pools, but respecting
-
* the minimum thresholds imposed by owners. It takes care of avoiding
-
* recursion because it may be called from a signal handler.
-
*/
-
extern void pool_flush_nonessential(void);
-
-
-
/* 动态分配一个 pool 元素大小的内存空间 */
-
/* Allocate a new entry for pool <pool>, and return it for immediate use.
-
* NULL is returned if no memory is available for a new creation.
-
*/
-
extern void * pool_refill_alloc(struct pool_head *pool);
-
-
-
-
/*
-
* Returns a pointer to type <type> taken from the
-
* pool <pool_type> or dynamically allocated. In the
-
* first case, <pool_type> is updated to point to the
-
* next element in the list.
-
*/
-
#define pool_alloc(pool)
-
({
-
void *__p;
-
if ((__p = (pool)->free_list) == NULL)
-
__p = pool_refill_alloc(pool);
-
else {
-
(pool)->free_list = *(void **)(pool)->free_list;
-
(pool)->used++;
-
}
-
__p;
-
})
-
-
-
-
/*
-
* Puts a memory area back to the corresponding pool.
-
* Items are chained directly through a pointer that
-
* is written in the beginning of the memory area, so
-
* there's no need for any carrier cell. This implies
-
* that each memory area is at least as big as one
-
* pointer. Just like with the libc's free(), nothing
-
* is done if <ptr> is NULL.
-
*/
-
#define pool_free(pool, ptr)
-
({
-
if ((ptr) != NULL) {
-
*(void **)(ptr) = (void *)(pool)->free_list;
-
(pool)->free_list = (void *)(ptr);
-
(pool)->used--;
-
}
-
})
-
-
-
-
#ifdef __cplusplus
-
}
-
#endif
-
- #endif
b,c文件(pools.c)
点击(此处)折叠或打开
-
#include "pools.h"
-
#include "standard.h"
-
-
-
/* 管理所有池的链表头 */
-
static struct list_head pools = LIST_HEAD_INIT(pools);
-
-
-
-
-
/* 池创建 */
-
/* Try to find an existing shared pool with the same characteristics and
-
* returns it, otherwise creates this one. NULL is returned if no memory
-
* is available for a new creation.
-
*/
-
struct pool_head * pool_create(char *name, uint32_t size, uint32_t flags)
-
{
-
struct pool_head *pool;
-
struct pool_head *entry;
-
struct list_head *start;
-
uint32_t align;
-
-
/* We need to store at least a (void *) in the chunks. Since we know
-
* that the malloc() function will never return such a small size,
-
* let's round the size up to something slightly bigger, in order to
-
* ease merging of entries. Note that the rounding is a power of two.
-
*/
-
-
align = 16;
-
size = (size + align - 1) & -align;
-
-
start = &pools;
-
pool = NULL;
-
-
list_for_each_entry(entry, &pools, list) {
-
if (entry->size == size) {
-
/* either we can share this place and we take it, or
-
* we look for a sharable one or for the next position
-
* before which we will insert a new one.
-
*/
-
if (flags & entry->flags & MEM_F_SHARED) {
-
/* we can share this one */
-
pool = entry;
-
break;
-
}
-
}
-
else if (entry->size > size) {
-
/* insert before this one */
-
start = &entry->list;
-
break;
-
}
-
}
-
-
if (!pool) {
-
pool = calloc(1, sizeof(*pool));
-
if (!pool)
-
return NULL;
-
if (name)
-
strlcpy(pool->name, (int8_t*)name, sizeof(pool->name));
-
pool->size = size;
-
pool->flags = flags;
-
list_add_tail(&pool->list,start);
-
}
-
pool->users++;
-
return pool;
-
}
-
-
-
-
/* 池销毁 */
-
void* pool_destroy(struct pool_head *pool)
-
{
-
if (pool)
-
{
-
pool_clear(pool); // 请看池中的空闲的元素
-
if (pool->used)
-
return pool;
-
pool->users--;
-
if (!pool->users)
-
{
-
list_del(&pool->list); // 从 pools 链表中删除
-
free(pool); // 把 pool 结构体占用的内存给释放了
-
}
-
}
-
return NULL;
-
}
-
-
-
-
/* 把池中的空闲的元素都给释放掉 */
-
/*
-
* This function frees whatever can be freed in pool <pool>.
-
*/
-
void pool_clear(struct pool_head *pool)
-
{
-
void *temp, *next;
-
if (!pool)
-
return;
-
-
next = pool->free_list;
-
while (next) {
-
temp = next;
-
next = *(void **)temp;
-
pool->allocated--;
-
free(temp);
-
}
-
pool->free_list = next;
-
-
/* here, we should have pool->allocate == pool->used */
-
}
-
-
-
-
/* 把池中非必要的元素给释放掉 */
-
/*
-
* This function frees whatever can be freed in all pools, but respecting
-
* the minimum thresholds imposed by owners. It takes care of avoiding
-
* recursion because it may be called from a signal handler.
-
*/
-
void pool_flush_nonessential(void)
-
{
-
static int recurse;
-
struct pool_head *entry;
-
-
if (recurse++)
-
goto out;
-
-
list_for_each_entry(entry, &pools, list) {
-
void *temp, *next;
-
//qfprintf(stderr, "Flushing pool %s
", entry->name);
-
next = entry->free_list;
-
while (next &&
-
entry->allocated > entry->minavail &&
-
entry->allocated > entry->used) {
-
temp = next;
-
next = *(void **)temp;
-
entry->allocated--;
-
free(temp);
-
}
-
entry->free_list = next;
-
}
-
out:
-
recurse--;
-
}
-
-
-
/* 动态分配一个 pool 元素大小的内存空间 */
-
/* Allocate a new entry for pool <pool>, and return it for immediate use.
-
* NULL is returned if no memory is available for a new creation. A call
-
* to the garbage collector is performed before returning NULL.
-
*/
-
void *pool_refill_alloc(struct pool_head *pool)
-
{
-
void *ret;
-
-
if (pool->limit && (pool->allocated >= pool->limit))
-
return NULL;
-
ret = calloc(1, pool->size);
-
if (!ret) {
-
pool_flush_nonessential();
-
ret = calloc(1, pool->size);
-
if (!ret)
-
return NULL;
-
}
-
-
pool->allocated++;
-
pool->used++;
-
return ret;
-
}
-
-
-
/* 销毁所有的池 */
-
int32_t dump_pools(void)
-
{
-
int32_t ret = OPER_OK;
-
-
return ret;
- }
c,辅助文件(standard.c)
点击(此处)折叠或打开
-
/*
-
* copies at most <size-1> chars from <src> to <dst>. Last char is always
-
* set to 0, unless <size> is 0. The number of chars copied is returned
-
* (excluding the terminating zero).
-
* This code has been optimized for size and speed : on x86, it's 45 bytes
-
* long, uses only registers, and consumes only 4 cycles per char.
-
*/
-
int32_t strlcpy(int8_t*dst, const int8_t*src, int32_t size)
-
{
-
int8_t *orig = dst;
-
if (size)
-
{
-
while (--size && (*dst = *src))
-
{
-
src++; dst++;
-
}
-
*dst = 0;
-
}
-
return dst - orig;
- }
d,辅助文件(types.h)
点击(此处)折叠或打开
-
#ifndef __TYPES_H__
-
#define __TYPES_H__
-
-
#ifdef __cplusplus
-
extern "C" {
-
#endif
-
-
/* Define to prevent recursive inclusion
-
-------------------------------------*/
-
#include <stdio.h> // 标准输入输出定义
-
#include <stdlib.h> // 标准函数库定义
-
#include <string.h> // memset
-
#include <unistd.h> // Unix标准函数定义,read,write...
-
#include <sys/types.h>
-
#include <sys/stat.h>
-
#include <fcntl.h> // 文件控制定义
-
#include <termios.h> // POSIX中断控制定义
-
#include <errno.h> // 错误号定义
-
#include <pthread.h> // pthread_t,pthread_create...
-
#include "error.h"
-
#include "debug.h"
-
-
/* 类型定义 */
-
typedef signed char int8_t;
-
typedef unsigned char uint8_t;
-
-
typedef signed short int16_t;
-
typedef unsigned short uint16_t;
-
-
typedef signed int int32_t;
-
typedef unsigned int uint32_t;
-
-
typedef signed long long int64_t;
-
typedef unsigned long long uint64_t;
-
-
-
#define BUFFER_SIZE 256
-
-
/* 1,COM,串口相关*/
-
#define COM_TYPE_UPPER_DEVICE 1
-
#define COM_TYPE_LOWER_DEVICE 2
-
-
#define COM_BUFFER_SIZE (BUFFER_SIZE)
-
-
-
/* 2,pools,池相关 */
-
-
-
-
/* 3,命令相关*/
-
#define CMD_DATA_LEN_MAX (BUFFER_SIZE)
-
-
-
-
-
#ifdef __cplusplus
-
}
-
#endif
-
- #endif
三,实例
1,头文件(command.h)
点击(此处)折叠或打开
-
#ifndef __COMMAND_H__
-
#define __COMMAND_H__
-
-
#ifdef __cplusplus
-
extern "C" {
-
#endif
-
-
/* Define to prevent recursive inclusion
-
-------------------------------------*/
-
#include "types.h"
-
-
-
/* 接收到的命令的来源等 */
-
typedef struct _cmd
-
{
-
int32_t fd;
-
pthread_t id;
-
void* data;
-
}cmd_t;
-
-
-
-
// 创建内存池
-
extern int32_t cmd_pool_create(void);
-
-
-
// 释放内存池
-
extern int32_t cmd_pool_destroy(void);
-
-
-
// 申请命令内存块,用以保存命令数据
-
extern int32_t cmd_alloc(cmd_t **param);
-
-
// 释放命令内存块
-
extern int32_t cmd_free(cmd_t *param);
-
-
#ifdef DEBUG_POOL
-
extern void cmd_pool_info(void);
-
#endif
-
-
-
#ifdef __cplusplus
-
}
-
#endif
-
- #endif
2,c文件(command.c)
点击(此处)折叠或打开
-
#include "command.h"
-
#include "pools.h"
-
-
-
static struct pool_head *cmd_head_pool = NULL;
-
static struct pool_head *cmd_data_pool = NULL;
-
-
-
// 创建内存池
-
int32_t cmd_pool_create(void)
-
{
-
int32_t ret = OPER_OK;
-
-
if (cmd_head_pool == NULL)
-
{
-
if((cmd_head_pool = pool_create("cmd_head", sizeof(cmd_t), MEM_F_SHARED)) == NULL)
-
{
-
ret = -POOL_CREATE_ERROR;
-
}
-
else
-
{
-
if (cmd_data_pool == NULL)
-
if((cmd_data_pool = pool_create("cmd_data", CMD_DATA_LEN_MAX, MEM_F_SHARED)) == NULL)
-
{
-
cmd_pool_destroy();
-
ret = -POOL_CREATE_ERROR;
-
}
-
}
-
}
-
-
#ifdef DEBUG_POOL
-
cmd_pool_info();
-
#endif
-
-
return ret;
-
}
-
-
-
#ifdef DEBUG_POOL
-
void cmd_pool_info(void)
-
{
-
struct pool_head *entry = cmd_head_pool;
-
printf("pool %s (%d bytes) : %d allocated (%u bytes), %d used
",entry->name, entry->size, entry->allocated,entry->size * entry->allocated, entry->used);
-
-
entry = cmd_data_pool;
-
printf("pool %s (%d bytes) : %d allocated (%u bytes), %d used
",entry->name, entry->size, entry->allocated,entry->size * entry->allocated, entry->used);
-
}
-
#endif
-
-
-
// 释放内存池
-
int32_t cmd_pool_destroy(void)
-
{
-
int32_t ret = OPER_OK;
-
-
#ifdef DEBUG_POOL
-
cmd_pool_info();
-
#endif
-
-
if(cmd_head_pool != NULL)
-
{
-
if(NULL != pool_destroy(cmd_head_pool))
-
{
-
ret = -POOL_DESTROY_ERROR;
-
}
-
else
-
{
-
if(cmd_data_pool != NULL)
-
if(NULL != pool_destroy(cmd_data_pool))
-
ret = -POOL_DESTROY_ERROR;
-
}
-
}
-
-
return ret;
-
}
-
-
-
// 申请命令内存块,用以保存命令数据
-
int32_t cmd_alloc(cmd_t **param)
-
{
-
int32_t ret = OPER_OK;
-
-
if((*param = (cmd_t*)pool_alloc(cmd_head_pool)) == NULL)
-
{
-
ret = -CMD_POOL_ALLOC_ERROR;
-
}
-
else
-
{
-
memset(*param,0,sizeof(cmd_t));
-
-
if(((*param)->data = pool_alloc(cmd_data_pool)) == NULL)
-
{
-
cmd_free(*param);
-
ret = -CMD_POOL_ALLOC_ERROR;
-
}
-
}
-
-
#ifdef DEBUG_POOL
-
cmd_pool_info();
-
#endif
-
-
return ret;
-
}
-
-
-
// 释放命令内存块
-
int32_t cmd_free(cmd_t *param)
-
{
-
if(param->data != NULL)
-
{
-
pool_free(cmd_data_pool,param->data);
-
param->data = NULL;
-
}
-
-
if(param != NULL)
-
{
-
pool_free(cmd_head_pool,param);
-
param = NULL;
-
}
-
- #ifdef DEBUG_POOL
-
cmd_pool_info();
- #endif
-
return OPER_OK;
- }
c,辅助文件(test.c)
点击(此处)折叠或打开
-
/*
-
* cmd pool begin
-
*/
-
static void cmd_pool_oper(void)
-
{
-
int32_t ret = OPER_OK;
-
-
printf("command pool test!
");
-
-
if((ret = cmd_pool_create()) != OPER_OK)
-
{
-
printf("Create command pool fail!
");
-
}
-
else
-
{
-
cmd_t* cmd_buf[5];
-
int32_t i = 0;
-
int32_t count = 0;
-
-
printf("Create command pool success!!!
");
-
-
memset(cmd_buf,0,sizeof(cmd_buf));
-
-
for(i = 0; i < 5; i++)
-
{
-
printf(" alloc
");
-
if(cmd_alloc(&cmd_buf[i]) != OPER_OK)
-
{
-
printf("Alloc buffer fail : %d
",i);
-
count = i;
-
break;
-
}
-
cmd_buf[i]->fd = i+1;
-
strcpy((char*)cmd_buf[i]->data,"hello");
-
}
-
-
printf("Alloc complete success!
");
-
// if(i >= 5) count = i;
-
-
for(i = 0 ; i < 5; i++)
-
{
-
printf("command %d fd : %d,data : %s
",(i+1),cmd_buf[i]->fd,(char*)cmd_buf[i]->data);
-
cmd_free(cmd_buf[i]);
-
}
-
-
if((ret = cmd_pool_destroy()) != OPER_OK)
-
printf("command pool destroy fail, still in use
");
-
else
-
printf("command pool destroy success!
");
-
}
-
-
}
-
-
-
-
void test_cmd_pool()
-
{
-
cmd_pool_oper();
-
}
-
-
/*
-
* cmd pool end
- */
d,测试结果
四,参考文件
1,《haproxy-1.5》源码
2,linux下双向链表的实现