📄 memb.c
字号:
//----------------------------------------------------
//Copyright (C), 2004-2009, lst.
//版权所有 (C), 2004-2009, lst.
//所属模块:内存池管理模块
//作者:lst
//版本:V1.0.0
//文件描述:提供固定块分配策略
//其他说明:
//修订历史:
// 2. ...
// 1. 日期:
// 作者:
// 新版本号:
// 修改说明:
//------------------------------------------------------
#include "inc_os.h"
//每个内存池都有一个mem_cell_pool类型的结构,这也是用固定块分配法进行分配的.
static struct mem_cell_pool tg_pool_of_cell_pool[cn_mem_pools];
static struct mem_cell_pool *pg_pool_of_cell_pool;
//----初始化固定块分配模块------------------------------------------------------
//功能: 初始化操作系统的固定块内存分配模块.
//参数: 无.
//返回: 无.
//----------------------------------------------------------------------------
bool_t module_init_memb(void)
{
static struct mem_cell_pool cell_pool;
cell_pool.cell_size = sizeof(struct mem_cell_pool);
cell_pool.continue_pool = tg_pool_of_cell_pool;
cell_pool.free_list = NULL;
cell_pool.pool_offset = (ptu32_t)&tg_pool_of_cell_pool[cn_mem_pools];
pg_pool_of_cell_pool = &cell_pool;
rsc_add_root_node(&cell_pool.memb_node,sizeof(struct mem_cell_pool),
"固定块分配池");
__semp_create_knl(&cell_pool.memb_semp,
cn_mem_pools,cn_mem_pools,"固定块分配池");
return true;
}
//----创建一个内存池-------------------------------------------------------
//功能: 初始化一个内存池,原始内存池的内存由用户提供。分配规则:
// 1.开始时,free_list指针空,continue_pool指向一个连续内存池。
// 2.如果free_list非空,新内存从free_list队列头部取。
// 3.如果free_list空,新内存从continue_pool中取。
// 4.释放内存时,把内存块链接到free_list队列,而不是返回continue_pool数组.
// 内存池是一个临界资源,操作时需要关闭中断,如果新申请的内存块全部链接到
// free_list,将会连续很长时间关闭中断,而现在采用的方法每次只操作一个内存块,
// 连续关中断的时间被降低到最小.
//参数: pool_original,最初由用户提供的内存池.
// capacital,原始内存池的尺寸,以块为单位。
// cell_size,若系统有对齐要求,必须为指针长度的整数倍.
// name,给内存池起个名字
//返回: 内存池指针.
//----------------------------------------------------------------------------
struct mem_cell_pool *mb_create(void *pool_original,uint32_t capacital,
uint32_t cell_size,char *name)
{
struct mem_cell_pool *pool;
if(capacital == 0)
return NULL;
//对齐参数检查,1、如果系统要求对齐访问,则块尺寸必须是指针尺寸的整数倍,内存池
//起始地址也是指针尺寸的整数倍。2、如果系统不要求对齐访问,则块尺寸大于指针尺寸
//就可以了。
#if(mem_align == 1)
if((cell_size % sizeof(void*) != 0)
|| (((ptu32_t)pool_original) % sizeof(void*) != 0)
|| (cell_size == 0))
return NULL;
#else
if(cell_size < sizeof(void*))
return NULL;
#endif
//分配一个内存池控制头
pool = (struct mem_cell_pool *)mb_malloc(pg_pool_of_cell_pool,0);
if(pool == NULL)
return NULL; //内存池控制头分配不成功
pool->continue_pool = (void*)pool_original; //连续池首地址
pool->free_list = NULL; //开始时空闲链表是空的
//设置连续池偏移地址
pool->pool_offset = (ptu32_t)pool_original + capacital*cell_size;
pool->cell_size = cell_size;
rsc_add_son(&pg_pool_of_cell_pool->memb_node,
&pool->memb_node,
sizeof(struct mem_cell_pool),
name);
__semp_create_knl(&pool->memb_semp,capacital,capacital,name);
return pool;
}
//----创建一个内核内存池-------------------------------------------------------
//功能:与mb_create的区别是,本函数需要调用者提供内存池控制块实体,而不是从池中
// 分配。因为cn_mem_pools是用户定义的,如果内核也与应用程序共享的话,将使
// 内核与应用程序发生耦合。
//参数: pool_cb,用户提供的内存池控制块
// pool_original,最初由用户提供的内存池.
// capacital,原始内存池的尺寸,以字节为单位,不能以块为单位,因为块尺寸将按
// 系统对齐要求调整,0表示直接从系统内存中申请.
// increment,内存池用完后,从系统内存中一次申请的块数.0表示不申请.
// cell_size,块尺寸,将按对齐要求调整,ARM中调整为8的整数倍.
// name,给内存池起个名字
//返回: 内存池指针.
//----------------------------------------------------------------------------
struct mem_cell_pool *__mb_create_knl(struct mem_cell_pool *pool,
void *pool_original,uint32_t capacital,
uint32_t cell_size,char *name)
{
pool->continue_pool = (void*)pool_original; //连续池首地址
pool->free_list = NULL; //开始时空闲链表是空的
//设置连续池偏移地址
pool->pool_offset = (ptu32_t)pool_original + capacital*cell_size;
pool->cell_size = cell_size;
rsc_add_son(&pg_pool_of_cell_pool->memb_node,
&pool->memb_node,
sizeof(struct mem_cell_pool),
name);
__semp_create_knl(&pool->memb_semp,capacital,capacital,name);
return pool;
}
//----分配一块内存-----------------------------------------------------------
//功能: 从制定内存池中分配一块内存,只能分配一块,而且不能保证连续两次分配的内存
// 地址是连续的.
//参数: pool,内存池指针
// timeout,超时设置,单位是毫秒,cn_timeout_forever=无限等待,0则立即按
// 超时返回。非0值将被向上调整为cn_tick_ms的整数倍
//返回: 申请成功返回内存地址,否则返回NULL.
//-----------------------------------------------------------------------------
void *mb_malloc(struct mem_cell_pool *pool,uint32_t timeout)
{
void *result;
if(pool == NULL)
return NULL;
//没有取得信号量,表明内存池空,这个信号量是保护内存池的,确保被分配的内存块
//不超过内存池的容量
if( ! semp_pend(&pool->memb_semp,timeout))
return NULL;
//下面的关调度(异步信号)是保护内存池控制块的,为什么不用互斥量呢?因为请求
//互斥量的过程也要关调度,而且关调度的时间还比这里长。
//注:从semp_pend到int_save_asyn_signal之间发生抢占是允许的,因为信号量已经
//取得,其他事件不可能把内存块分配光。
int_save_asyn_signal();
if(pool->free_list != NULL) //空闲队列中有内存块
{
result = pool->free_list; //取空队列表头部的内存块
pool->free_list = *(void**)(pool->free_list); //空闲队列下移一格.
}else //空闲队列中无内存块,从连续池中取
{
pool->pool_offset -= pool->cell_size; //偏移地址调整
//分配偏移地址处的内存块
result = (void*)pool->pool_offset;
}
int_restore_asyn_signal();
return result;
}
//----释放内存--------------------------------------------------------------
//功能: 释放内存,把使用完毕的内存块放回制定内存池,内存池和内存块必须匹配,否则
// 会发生灾难性的错误.新释放的块链接到 free_list 队列中,而不是放回连续池
// 中,块也不重新返回系统堆.内存池从系统堆分配内存是单向的,一经分配永不释放.
//参数: block,待释放的内存块指针
// pool,目标内存池.
//返回: 无
//-----------------------------------------------------------------------------
void mb_free(struct mem_cell_pool *pool,void *block)
{
void *pl_continue;
uint32_t block_sum;
if(pool == NULL)
return;
pl_continue = pool->continue_pool;
block_sum = semp_query_capacital(&pool->memb_semp);
//被释放块合法性检查:1、地址不能低于内存池首地址
// 2、地址不能高于内存池末地址
// 3、地址必须是块首地址,即偏移必须是块尺寸的整数倍
if((block < pl_continue)
||((ptu32_t)block>=((ptu32_t)pl_continue+pool->cell_size*block_sum))
||(((ptu32_t)block-(ptu32_t)pl_continue) % pool->cell_size != 0))
return ;
int_save_asyn_signal(); //进入临界区
*(void**)block = pool->free_list; //释放块指向空闲队列头
pool->free_list = block; //调整空闲队列头的位置
int_restore_asyn_signal(); //退出临界区
semp_post(&pool->memb_semp);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -