📄 mems.c
字号:
u32l_start_time = y_get_time();
do
{
wait=false;
if(tg_mem_global.ua_free_block_max < size)
{//最大的可分配块尺寸小于请求的内存,没有内存可以分配
int_save_asyn_signal();
wait=true; //如果是经过了阻塞后重新执行,while循环需要再次判断
//是否有足够的内存分配.
__y_cut_ready_event(pg_event_running);
pg_event_running->next = NULL;
pg_event_running->previous = NULL;
pg_event_running->wait_mem_size = size; //填充等待的字节数
event = tg_mem_global.mem_sync; //获取内存等待表指针
//以下把事件置入内存等待队列中
pg_event_running->sync_head = &tg_mem_global.mem_sync;
if(event == NULL) //等待队列空
{
pg_event_running->multi_next = pg_event_running;
pg_event_running->multi_previous = pg_event_running;
tg_mem_global.mem_sync = pg_event_running;
}else
{
do
{//本循环找到第一个请求内存大于新事件的事件.
if(event->wait_mem_size > size)
event = event->multi_next;
else
break;
}while(event != tg_mem_global.mem_sync);
//如果没有找到申请内存比新事件长的事件,新事件插入队列尾,而
//队列尾部就是event_wait的前面,此时event恰好等于event_wait
//如果找到剩余延时时间长于新事件的事件,新事件插入该事件前面.
//所以无论前面循环找到与否,均可使用下列代码
pg_event_running->multi_next = event;
pg_event_running->multi_previous = event->multi_previous;
event->multi_previous->multi_next = pg_event_running;
event->multi_previous = pg_event_running;
}
pg_event_running->last_status.all
= pg_event_running->event_status.all;
pg_event_running->event_status.bit.wait_memory = 1;
if(timeout != cn_timeout_forever)
{
pg_event_running->event_status.bit.wait_overtime = 1;
__y_addto_delay(timeout_ticks-u32l_rest_time);
}
int_restore_asyn_signal(); //打开中断才能实现调度
//检查从哪里返回,是超时还是有事件释放内存
if(pg_event_running->event_status.bit.wait_memory)
{//说明同步条件未到,从超时返回,应从内存同步队列中取出事件。
pg_event_running->event_status.bit.wait_memory = 0;
return false; //超时返回
}else //同步返回条件达成,说明有线程释放内存,进入下一次while循环
{ //检查是否有足够的内存,
u32l_rest_time = y_get_time() - u32l_start_time;
//在这里做这个条件判断是必要的,其他线程释放内存会激活本事件,
//但释放内存的时间可能与超时时间临界,或者由于优先级的关系本事件
//不能立即得到执行,本事件真正开始执行时overtime条件也已经成立。
//如果此时内存仍然不足,就应该按超时返回
if((u32l_rest_time >= timeout_ticks)
&&(tg_mem_global.ua_free_block_max < size))
{
return false;
}
}
}
}while(wait==true);
return true; //return true前是不开中断的,以免在分配内存之前发生中断.
}
//----把事件放入等待队列-------------------------------------------------------
//功能: 把事件直接放进等待队列,不调度.等待队列是一个按请求的内存从小到大排列的
// 双向循环链表.
//参数: event,待进入等待队列的事件指针
//返回: 无
//-----------------------------------------------------------------------------
void __m_wait_memory(struct event_script *event)
{
struct event_script *pl_event;
ptu32_t size;
size = event->wait_mem_size;
pl_event = tg_mem_global.mem_sync; //获取内存等待表指针
if(pl_event == NULL) //延时队列空
{
event->next = event;
event->previous = event;
tg_mem_global.mem_sync = event;
}else
{
do
{//本循环找到第一个请求内存大于新事件的事件.
if(pl_event->wait_mem_size > size)
pl_event = pl_event->next;
else
break;
}while(pl_event == tg_mem_global.mem_sync);
//如果没有找到申请内存比新事件长的事件,新事件插入队列尾,而队列
//尾部就是event_wait的前面,此时event恰好等于event_wait
//如果找到剩余延时时间长于新事件的事件,新事件插入该事件前面.
//所以无论前面循环找到与否,均可使用下列代码
event->next = pl_event;
event->previous = pl_event->previous;
pl_event->previous->next = event;
pl_event->previous = event;
}
return;
}
//----回收running事件申请的内存------------------------------------------------
//功能: 在内存管理的事件id表中查找由event_id事件申请的局部内存,如果有,则登记
// enum_mem_leak错误,并强行释放之。
//参数: event_id,目标事件id
//返回: 无
//-----------------------------------------------------------------------------
void __m_cleanup(uint16_t event_id)
{
}
//----内存结构初始化-----------------------------------------------------------
//功能: 初始化内存数据结构,但不初始化堆
//参数: 无
//返回: 无
//备注: 1.本函数在初始化完成之前调用,中断尚未开启,无需考虑关闭中断的问题.
// 2.软件启动后首先调用本函数,启动静态分配功能,但还不具备动态分配功能.
//-----------------------------------------------------------------------------
bool_t module_init_heap_static(void)
{
tg_mem_global.dynamic = false;
tg_mem_global.static_bottom = (uint8_t*)align_up((ptu32_t)cfg_heap_bottom);
tg_mem_global.heap_bottom = tg_mem_global.static_bottom;
tg_mem_global.heap_top=(uint8_t*)align_down((ptu32_t)cfg_heap_top);
return true;
}
//----初始化内存堆-------------------------------------------------------------
//功能:1.从堆中分配访问控制结构所需的内存,位置在堆的顶部,占用整数块
// 2.初始化内存分配控制结构,初始化全局内存结构 struct mem_global
// 3.初始化内存分配表
//返回:若出错则返回cn_mem_page_error,否则返回cn_no_error
//备注: 1.本函数在初始化完成之前调用,中断尚未开启,无需考虑关闭中断的问题.
// 2.调用本函数前,只能能执行静态分配功能,不能执行动态分配功能.
// 3.目前只适用于不带mmu的情况,带mmu特别是支持多进程的情况还没有想好。
//-----------------------------------------------------------------------------
bool_t module_init_heap_dynamic(void)
{
ptu32_t ua_temp,ua_temp1=0,ua_temp2,ua_temp3 = 0,ua_faction;
ptu32_t ua_pages,ua_table_size=0;
ufast_t uf_classes,uf_grades;
ucpu_t ***pppl_bitmap,**ppl_bitmap,*pl_bitmap;
ufast_t *pl_classes;
// for(ua_temp=0;ua_temp<cn_point_bit;ua_temp++)
// { //计算页尺寸中1的个数,
// if(cn_page_size&(1<<ua_temp))
// ua_temp1++;
// }
// if(ua_temp1!=1) //页尺寸中只有一个1时说明正好是2的整数次方
// return(enum_mem_page_error);
//注释掉的原因:cn_page_size将由配置程序生成,肯定是2的整数次方.
tg_mem_global.dynamic = true;
#if (cn_mmu == false)
ua_faction=(ptu32_t)(tg_mem_global.heap_top-tg_mem_global.heap_bottom);
//计算堆的总页数,取整页,舍去余数部分
ua_pages= ua_faction>>cn_page_size_suffix_zero;
//计算堆页数调整后的余数,可用于内存控制结构使用。
ua_faction=ua_faction-(ua_pages<<cn_page_size_suffix_zero);
tg_mem_global.heap_top -=ua_faction;
#else
// ua_faction = tg_mem_global.heap_top;
// //向下对其页边界
// tg_mem_global.heap_top = tg_mem_global.heap_top & (~(cn_page_size-1));
// //向上对其页边界
// tg_mem_global.heap_bottom = (tg_mem_global.heap_bottom + cn_page_size -1)
// & (~(cn_page_size-1));
// ua_faction -= tg_mem_global.heap_top;
#endif
if(ua_pages < 2) //如果堆中页数小于2页,控制结构可能还要占用1页,还有意义吗?
{
return false;
}
__mutex_createe_knl(&tg_mem_mutex,true,"dynamic memory allocation");
ua_temp = __m_calculate_expense(ua_pages); //初估控制结构需要的字节数
if(ua_faction < ua_temp)
{
//初估控制结构除ua_faction外还需要的页数
ua_temp = (ua_temp-ua_faction+cn_page_size-1)>>cn_page_size_suffix_zero;
for(ua_temp1 = ua_temp; ua_temp1 > 0; ua_temp1--)
{//初估的页数肯定大于或等于实际需要的页数,尤其是内存页数较多时.
//估计值从初估的页数开始逐一减小,直到合适为止.
ua_temp2 = __m_calculate_expense(ua_pages-ua_temp1);//重估控制结构字节数
ua_temp3 = (ua_temp2-ua_faction+cn_page_size-1)
>> cn_page_size_suffix_zero;//重新计算控制结构页数
if(ua_temp3 >= ua_temp1)
//当所需页数刚好大于或等于估计值时,循环终止
break;
}
ua_pages = ua_pages -ua_temp3;//实际可分配的页数,u32_temp3为控制结构页数
// (tg_mem_global.heap_top) -= 1;
tg_mem_global.heap_top
-= ua_temp3<<cn_page_size_suffix_zero; //调整堆顶部位置
}
tg_mem_global.ua_pages_num = ua_pages;
tg_mem_global.free_pages_num = ua_pages;
//内存控制结构清零
memset(tg_mem_global.heap_top,0,ua_faction+(ua_temp3<<cn_page_size_suffix_zero));
//计算总阶数,即一共有多少种页尺寸,方法:地址长度减去ua_pages中前导0的数量
//例如,ua_pages=5,最高位位置是bit2,有29个前导0,页尺寸有1,2,4页3种,阶数=3
uf_grades=cn_point_bit-__m_leading_zero((uint8_t *)&ua_pages,sizeof(ptu32_t));
tg_mem_global.uf_grades = uf_grades; //总阶数
tg_mem_global.ua_block_max=cn_page_size<<(uf_grades-1);//最高阶块尺寸
tg_mem_global.ua_free_block_max=tg_mem_global.ua_block_max; //最大可用块尺寸
//计算位图指针表所需的指针数
ua_table_size=0;
for(ua_temp=0;ua_temp<uf_grades;ua_temp++)
{//遍历各阶
ua_temp1 = ua_pages>>ua_temp; //计算ua_temp阶0级位图位数
do
{
//计算下一级位图的位数
ua_temp1=(ua_temp1+cn_cpu_bits-1)>>cn_cpu_bits_suffix_zero;
ua_table_size++; //需要一个指针指向该级位图首地址
}while(ua_temp1>1); //下一级位图超过1位(本级超过cn_cpu_bits位),继续循环
}
//事件指针id表,详细说明见mem_global_t类型定义部分.
tg_mem_global.index_event_id=(uint16_t*)tg_mem_global.heap_top;
//各阶的位图级数表指针,每阶用一个ufast_t型的数表示该阶的位图级数
ua_temp = (ptu32_t)(tg_mem_global.index_event_id+ua_pages);
ua_temp = (ua_temp+sizeof(ufast_t)-1)&(~(sizeof(ufast_t)-1)); //对齐
pl_classes=(ufast_t *)ua_temp;
tg_mem_global.p_classes=pl_classes; //各阶空闲金字塔级数表首指针
//随后是各级分配表指针的指针首址
ua_temp = (ptu32_t)(pl_classes+uf_grades);
ua_temp = (ua_temp+sizeof(void *)-1)&(~(sizeof(void *)-1)); //对齐
pppl_bitmap=(void*)ua_temp;
tg_mem_global.ppp_bitmap=pppl_bitmap; //各阶空闲金字塔位图指针表的指针表的首指针
ppl_bitmap=(ucpu_t **)(pppl_bitmap+uf_grades); //空闲金字塔位图指针表的指针
pl_bitmap=(ucpu_t *)(ppl_bitmap+ua_table_size); //空闲金字塔位图指针表
//填充各索引表和分配表
for(ua_temp=0;ua_temp<uf_grades;ua_temp++)
{//遍历各阶
ua_temp1 = ua_pages>>ua_temp; //ua_temp阶位图总位数
uf_classes=0; //ua_temp阶的位图级数
pppl_bitmap[ua_temp]=ppl_bitmap; //ua_temp阶位图表的指针
do
{
ucpu_t msk=~0; //类型位宽未知,用此方法置全1
ua_temp3=ua_temp1>>cn_cpu_bits_suffix_zero; //本级表的大小(整数部分)
ua_temp1=ua_temp1%cn_cpu_bits; //本路径级表的大小(余数部分)
if(ua_temp1==0)
//表中没有多余的位,无需处理
ua_temp1=ua_temp3; //本级位图所占字数是下一级的位数
else
{//表中有多余的位,置1,使多余的位等同于已分配的位.
msk=msk<<ua_temp1; //使多余的位置1
*(pl_bitmap+ua_temp3) |=msk; //修改位图中相应的位
ua_temp1=ua_temp3+1; //路径表修正,加上余数部分
}
*ppl_bitmap++ = pl_bitmap; //记录本级位图指针
pl_bitmap +=ua_temp1; //位图指针指向下一级位图起始地址
uf_classes++; //ua_temp阶的级数增量
}while(ua_temp1>1); //直到遍历本阶所有位图级
pl_classes[ua_temp]=uf_classes; //该级路径表深度
}
// if(cn_mem_recycle) //提供内存回收功能,建议小内存不要使用内存回收
// {//此时初始化未完成,无需考虑中断关闭的问题.
// pg_mem_record_free=__inc_record_link();
// }
return true;
}
//----准静态内存分配-----------------------------------------------------------
//功能:分配内存,调整heap_bottom指针
//参数:size,欲分配的内存块尺寸
//返回:分配的内存指针,NULL表示没有内存可以分配
//备注: 1.准静态分配与静态内存分配类似,没有保护措施,正确性要程序员自己保证.这种
// 分配方法也不会引起阻塞,在执行module_init_heap_dynamic之前,所有的内存分配
// 均采用准静态分配
// 2.本函数在初始化完成之前调用,中断尚未开启,无需考虑关闭中断的问题.
//-----------------------------------------------------------------------------
void *__m_static_malloc(ptu32_t size)
{
uint8_t *temp;
temp = tg_mem_global.heap_bottom; //保存当前堆底
//留下保存块尺寸的空间后对齐
tg_mem_global.heap_bottom = (uint8_t *)align_up
((ptu32_t)tg_mem_global.heap_bottom + sizeof(ptu32_t));
if((tg_mem_global.heap_top-tg_mem_global.heap_bottom) < size)
{
tg_mem_global.heap_bottom = temp; //恢复当前堆底
return NULL; //内存不足,返回
}
//新分配的内存尺寸保存在当前堆底前面
temp = tg_mem_global.heap_bottom - sizeof(ptu32_t);
*(ptu32_t *)temp = size; //保存申请的内存块尺寸
temp = tg_mem_global.heap_bottom; //保存分配给用户的内存块地址
tg_mem_global.heap_bottom += size; //移动堆底部指针
tg_mem_global.heap_bottom = (uint8_t *)align_up
((ptu32_t)tg_mem_global.heap_bottom);//对齐
return(temp);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -