📄 mems.c
字号:
}break;
case 0 ... cn_event_id_limit :
{//单页局部分配:id,
uf_free_grade_th = 0;
}break;
default :
{//指针错误
return 0;
}break;
}
return cn_page_size << uf_free_grade_th;
}
}
//----释放从堆分配的内存-------------------------------------------------------
//功能: 释放从堆中分配的一块内存,如果此时动态分配还没有初始化,则执行准静态
// 内存释放。释放内存后,重新计算最大空闲块的尺寸,如果有事件在内存同步
// 队列中,则把等待的内存尺寸小于新的最大空闲块尺寸的事件激活。
//参数:pl_mem,待释放的内存指针
//返回:错误返回flase,正确时返回true
//-----------------------------------------------------------------------------
bool_t m_free(void * pl_mem)
{
ptu32_t ua_temp1;
ptu32_t ua_word_offset;
ufast_t uf_word_shift; //字内偏移量
ptu32_t ua_pages_no;
ufast_t uf_grade_th,uf_free_grade_th;
ufast_t uf_classes;
ufast_t *pl_classes;
ucpu_t ***pppl_bitmap;
ucpu_t **ppl_bitmap;
ucpu_t *pl_bitmap;
uint16_t *pl_id,id=0xffff;
struct event_script *event;
ptu32_t ua_bit_num;
ucpu_t uc_msk;
if(pl_mem == NULL)
return false;
//下面用到的tg_mem_global中的dynamic、heap_bottom和heap_top成员,在启动多
//事件调度后,均不再变化,并发读是安全的。
if(tg_mem_global.dynamic==false)
return(__m_static_free(pl_mem)); //内存尚未初始化,执行准静态内存分配
if(((uint8_t*)pl_mem<tg_mem_global.heap_bottom)
|| ((uint8_t*)pl_mem>=tg_mem_global.heap_top))
{
y_error_login(enum_mem_error,NULL); //欲释放的内存不在内存堆中,直接退出.
return false;
}
//计算释放的内存块的首页页号
ua_pages_no=(ptu32_t)((ptu32_t)pl_mem-(ptu32_t)tg_mem_global.heap_bottom)
>>cn_page_size_suffix_zero;
mutex_pend(&tg_mem_mutex,cn_timeout_forever);
//查找释放的内存块的阶号,从0起计.通过阶号也可以确定内存块的大小.
//确定内存块的类型,局部内存需要知道拥有该内存的事件id,
//全局内存无需清理内存分配跟踪表,无需知道拥有该内存的事件id
pl_id = &tg_mem_global.index_event_id[ua_pages_no];
switch(pl_id[0])
{
case 0xffff :
{ //双页局部内存,-1+id
id = pl_id[1];
uf_free_grade_th = 1;
}break;
case 0xfffe :
{ //多页局部内存:-2+id+阶号
id = pl_id[1];
uf_free_grade_th = pl_id[2];
}break;
case 0xfffd :
{ //单页全局内存:-3
uf_free_grade_th = 0;
}break;
case 0xfffc :
{ //双(多)页全局内存:-4+阶号.
uf_free_grade_th = pl_id[1];
}break;
case 0 ... cn_event_id_limit :
{ //单页局部内存:id,
id = pl_id[0];
uf_free_grade_th = 0;
}break;
default :
{
y_error_login(enum_mem_error,NULL); //指针有错,直接退出
return false;
}break;
}
/*
if(0xffff != id)
{ //待释放的是局部内存,需要删除内存分配记录结点.
//绝大多数情况下,id 等于running,但也可能有例外,不能直接用running指针.
event = __y_lookup_id(id);
record = event->held_memory;
if(record == NULL)
{
y_error_login(enum_mem_error,NULL); //链表空,直接退出.
return false;
}
if(record->address == pl_mem)
{ //与第一个记录匹配
event->held_memory = record->next;
record->next = pg_mem_record_free; //被删除的结点连到free表头部
pg_mem_record_free = record; //移动free指针
} else
{
for(;record->next != NULL;record = record->next)
//循环直到找到待删除的结点的前一个结点
if(record->next->address == pl_mem)
break;
if(record->next ==NULL)
{
y_error_login(enum_mem_error,NULL);//链表中没有搜索到记录,直接退出
return false;
}else
{ //找到记录
struct mem_record *p;
p = record->next; //取得待删除的结点
record->next = p->next; //删除结点
p->next = pg_mem_record_free; //被删除的结点连到free表头部
pg_mem_record_free=p; //移动free指针
}
}
}
*/
pppl_bitmap=tg_mem_global.ppp_bitmap; //空闲金字塔位图指针的指针表的首指针
ppl_bitmap=pppl_bitmap[uf_free_grade_th];//该阶空闲金字塔位图指针表的首址
pl_bitmap=ppl_bitmap[0]; //空闲金字塔位图指针
pl_classes=tg_mem_global.p_classes; //读取各阶空闲金字塔级数表指针.
uf_classes=pl_classes[uf_free_grade_th]-1; //该阶空闲金字塔最高一级指针在
//ppl_bitmap中的偏移量
//计算位偏移
ua_word_offset =ua_pages_no>>uf_free_grade_th;
//计算字内位偏移,下面算式起取模的作用
uf_word_shift=ua_word_offset&cn_low_xbit_msk[cn_cpu_bits_suffix_zero];
ua_word_offset=ua_word_offset>>cn_cpu_bits_suffix_zero; //计算字偏移
//空闲页数增加
tg_mem_global.free_pages_num += 1<<uf_free_grade_th;
//下面开始在bitmap表标记本次释放情况
for(uf_grade_th = 0; uf_grade_th <= uf_free_grade_th; uf_grade_th++)
{//从0阶直到当前阶(不包含),处理阶号低于当次申请的内存的位图.
//块的起始页号右移阶号即得到在该阶0级位图中的偏移
ua_word_offset =ua_pages_no>>uf_grade_th;
ppl_bitmap=pppl_bitmap[uf_grade_th]; //取得该级分配表指针表的首址
ua_bit_num=1<<(uf_free_grade_th-uf_grade_th); //计算掩码位数
for(ua_temp1=0;ua_temp1<pl_classes[uf_grade_th];ua_temp1++)
{//从低级到高级遍历该阶各级位图
pl_bitmap = ppl_bitmap[ua_temp1]; //相应级相应路径分配表首址
//计算字内位偏移,下面算式起取模的作用
uf_word_shift=ua_word_offset&cn_low_xbit_msk[cn_cpu_bits_suffix_zero];
ua_word_offset = ua_word_offset>>cn_cpu_bits_suffix_zero; //字偏移
if(ua_bit_num>=cn_cpu_bits) //ua_bit_num保存的是需要清0的位
{//位数大于或等于1个字宽,因为采用2的n次方分级,所以要处理的位数肯定
//是整数个字,按整数个字清0就可以了.
//计算字数,也是下一级位图中需清0的位数
ua_bit_num >>=cn_cpu_bits_suffix_zero;
//uc_word_shift在这里当临时变量使用
for(uf_word_shift =0; uf_word_shift < ua_bit_num; uf_word_shift++)
pl_bitmap[ua_word_offset+uf_word_shift]=0;
}else if(ua_bit_num > 0)
{//位数小于一个字宽,且大于0
uc_msk=~(cn_low_xbit_msk[ua_bit_num]<<uf_word_shift);
pl_bitmap[ua_word_offset] &=uc_msk;
if(pl_bitmap[ua_word_offset] == uc_msk)
//被清0的位所在的字全1全1->有0,该字对应的下一级位图相应位清0
ua_bit_num=0;
else
break;
}else
{//前一次操作使一个字从全1->有0,该字对应的下一级路径相应位清0
pl_bitmap[ua_word_offset] &= ~(1<<uf_word_shift);
if(pl_bitmap[ua_word_offset] == ~(1<<uf_word_shift))
//被清0的位所在的字全1->有0,该字对应的下一级位图相应位清0
;
else
break;
}
}
}
for(;uf_grade_th<tg_mem_global.uf_grades;uf_grade_th++)
{//当前阶(包含)到最高阶,处理阶号高于或等于当次申请的内存的位图.每次只需清1位
//块的起始页号右移阶号即得到在该阶0级位图中的偏移
ua_word_offset=ua_pages_no>>uf_grade_th;
if(ua_word_offset>=tg_mem_global.ua_pages_num>>uf_grade_th)
//该阶无对应块,这是可能的,比如一个共10页的内存,第9页和第10页都在第3阶中
//无映射.条件式右边是本阶总块数,左端是从0起计的偏移量,最大只能是总块数-1
break;
ppl_bitmap=pppl_bitmap[uf_grade_th]; //取得该级分配表指针表的首址
for(ua_temp1=0;ua_temp1<pl_classes[uf_grade_th];ua_temp1++)
{
pl_bitmap = ppl_bitmap[ua_temp1];
//计算字内位偏移,下面算式起取模的作用
uf_word_shift=ua_word_offset&cn_low_xbit_msk[cn_cpu_bits_suffix_zero];
ua_word_offset=ua_word_offset>>cn_cpu_bits_suffix_zero; //字偏移
pl_bitmap[ua_word_offset] &= ~(1<<uf_word_shift);
if(pl_bitmap[ua_word_offset] == ~(1<<uf_word_shift))
//被清0的位所在的字全1->有0,该字对应的下一级位图相应位清0
;
else
break;
}
}
//刷新最大空闲内存块
uf_grade_th=tg_mem_global.uf_grades-1; //取最高阶的阶号
do{
uf_classes = pl_classes[uf_grade_th]; //第uf_grade_th阶的总级数
ppl_bitmap = pppl_bitmap[uf_grade_th]; //位图索引表指针
pl_bitmap = ppl_bitmap[uf_classes-1]; //最高级位图指针
if(*pl_bitmap != (~0))
{//路径顶端只要不是全1就表示该阶肯定有空闲块.
//根据阶号计算最大空闲块的尺寸.
tg_mem_global.ua_free_block_max=cn_page_size<<uf_grade_th;
break;
}
}while(uf_grade_th-- >0); //从最高阶(最大块)扫描到0阶
// if(0xffff == id)
// {//如果不加这句,出现下述情况时将发生内存错误
//1.申请局部内存,堆用完-->记录本次分配后-->发现pg_mem_record_free空
// -->没有内存增加链表长度.
//2.释放全局内存,使得又有内存可以分配.
//3.此时申请局部内存,记录时可能出错.
// if(pg_mem_record_free==NULL)
// pg_mem_record_free=__inc_record_link();
// }
mutex_post(&tg_mem_mutex);
pg_event_running->local_memory--;
//把内存等待队列中申请内存之和小于当前可用最大内存的几个事件放到ready队列
//等待队列是双向循环链表
int_save_asyn_signal();
if(tg_mem_global.mem_sync != NULL)
{
event = tg_mem_global.mem_sync; //取等待队列头
ua_temp1 = tg_mem_global.ua_free_block_max;
while(1)
{
//ua_word_offset在此权当临时变量使用,规格化当前事件需要的内存.
ua_word_offset = __m_get_grade(event->wait_mem_size)
<< cn_page_size_suffix_zero;
if(ua_word_offset <= ua_temp1)
{//事件等待的内存量小于最大空闲内存块,把事件放到就绪队列
//剩余可用尺寸减少当前激活的事件所申请的内存,但并不实际执行申请
ua_temp1 -= __m_get_grade(event->wait_mem_size)
<< cn_page_size_suffix_zero;
event->last_status.all = event->event_status.all;
event->event_status.bit.wait_memory = 0;
if(event->event_status.bit.wait_overtime)
__y_resume_delay(event);
event->event_status.bit.wait_overtime = 0;
if(event->multi_next == event->multi_previous)
{//是最后一个事件
tg_mem_global.mem_sync = NULL;
break;
}else
{
tg_mem_global.mem_sync = event->multi_next;
event->multi_next->multi_previous = event->multi_next;
event->multi_previous->multi_next = event->multi_previous;
}
__y_event_ready(event);
}else
break;
}
}
int_restore_asyn_signal(); //恢复中断状态
return(true);
}
//----查询最大可用内存块-------------------------------------------------------
//功能:返回最大可用内存块的尺寸
//参数:无
//返回:内存块字节数
//-----------------------------------------------------------------------------
ptu32_t m_get_max_free_mem(void)
{
return tg_mem_global.ua_free_block_max;
}
//----查询堆空间大小---------------------------------------------------------
//功能:返回堆空间大小
//参数:无
//返回:内存堆字节数
//-----------------------------------------------------------------------------
ptu32_t m_get_heap_size(void)
{
return tg_mem_global.ua_pages_num<<cn_page_size_suffix_zero;
}
//----查询总空闲内存大小-------------------------------------------------------
//功能:返回空闲内存字节数
//参数:无
//返回:空闲内存字节数
//-----------------------------------------------------------------------------
ptu32_t m_get_free_mem(void)
{
return tg_mem_global.free_pages_num<<cn_page_size_suffix_zero;
}
//----查询页尺寸---------------------------------------------------------------
//功能:返回页字节数
//参数:无
//返回:页字节数
//-----------------------------------------------------------------------------
ptu32_t m_get_page_size(void)
{
return cn_page_size;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -