⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mems.c

📁 新一代基于事件的嵌入式操作系统dyos在三星的s3c44b0的arm芯片上的完整移植代码
💻 C
📖 第 1 页 / 共 4 页
字号:
//----释放准静态分配的内存块---------------------------------------------------
//功能:释放准静态分配的一个内存块
//参数:pl_mem,待释放的内存块指针
//返回:true = 成功释放,false =  释放失败
//备注: 1.准静态分配与静态内存分配类似,没有保护措施,正确性要程序员自己保证.这种
//      分配方法也不会引起阻塞,在执行module_init_heap_dynamic之前,所有的内存分配
//      均采用准静态分配
//      2.本函数在初始化完成之前调用,中断尚未开启,无需考虑关闭中断的问题.
//-----------------------------------------------------------------------------
bool_t __m_static_free(void * pl_mem)
{
    return true;
}

//----从内存堆中分配内存-------------------------------------------------------
//功能:1.规格化内存尺寸,计算满足要求的最小内存尺寸,计算该块内存尺寸的阶数
//      2.读取该级访问路径深度,沿访问路径逐级查找,直到找到空闲内存为止。
//      3.重置内存分配表
//      4.把内存分配信息置入链表中,以备清理内存用.
//      5.如果内存不足,则把事件挂在tg_mem_global.event_wait下,并引发事件切换.
//参数:size,欲分配的内存块尺寸
//      timeout,超时设置,单位是毫秒,cn_timeout_forever=无限等待,0则立即按
//      超时返回。非0值将被向上调整为cn_tick_ms的整数倍
//返回:分配的内存指针,NULL表示没有内存可以分配
//备注: 如果在多事件调度启动前调用本函数,记录拥有者时全部算在系统服务事件中。
//      系统服务事件永不结束,故等同于全局分配。
//-----------------------------------------------------------------------------
void *m_malloc(ptu32_t size,uint32_t timeout)
{
    uint8_t *ua_address;
    ufast_t  uf_grade_th;
    bool_t   en_scheduler;
    void *result;
    uint16_t *pl_id,id;
    uint32_t page;

    //启动多事件调度后,dynamic成员不会再发生变化,即使并发访问也是安全的
    if(tg_mem_global.dynamic==false)
        return(__m_static_malloc(size));  //内存尚未初始化,执行准静态内存分配
    //不能在此直接判断size是否满足,因为取得互斥量前可能发生切换而判断无效.
//    int_save_asyn_signal();
    if(mutex_pend(&tg_mem_mutex,timeout) == false)
        return NULL;
    en_scheduler = y_query_sch();
    if((tg_mem_global.ua_free_block_max < size)
                && ((timeout == 0) || !en_scheduler))
    {
        result = NULL;
    }else
    {
        if( !__m_check_memory(size,timeout) )            //没有合适的空闲内存块
        {
            result = NULL;
        }else    //有合适的空闲内存块
        {
            uf_grade_th=__m_get_grade(size);          //取阶号
            ua_address=__malloc_block(uf_grade_th); //申请内存
            pg_event_running->local_memory++;

//            __record_mem(ua_address,uf_grade_th);   //记录内存
            //阅读以下条件句请结合mem_global_t中index_event_id成员定义的注释.
            pl_id = tg_mem_global.index_event_id;
            id = pg_event_running->event_id;
            page = (ptu32_t)(ua_address-tg_mem_global.heap_bottom)
                    >>cn_page_size_suffix_zero;
            if(uf_grade_th==0)
            {//分配1页
                pl_id[page] = id;
            }else if(uf_grade_th==1)
            {//分配2页
                pl_id[page] = -1;
                pl_id[page+1] = id;
            }else
            {   //分配多页
                pl_id[page] = -2;
                pl_id[page+1] = id;
                pl_id[page+2] = uf_grade_th;
            }
            result = ua_address;
        }
    }
    mutex_post(&tg_mem_mutex);
//    int_restore_asyn_signal();
    return result;
}

//----分配全局内存-------------------------------------------------------------
//功能:1.规格化内存尺寸,计算满足要求的最小内存尺寸,计算该块内存属于第几阶。
//      2.读取该级访问路径深度,沿访问路径逐级查找,直到找到空闲内存为止。
//      3.重置内存分配表
//      4.如果内存不足,则把事件挂在tg_mem_global.event_wait下,并引发事件切换.
//参数:size,欲分配的内存块尺寸
//      timeout,超时设置,单位是毫秒,cn_timeout_forever=无限等待,0则立即按
//      超时返回。非0值将被向上调整为cn_tick_ms的整数倍
//返回:分配的内存指针,NULL表示没有内存可以分配
//备注: 用此函数分配的内存,并不会在事件完成时被收回.
//-----------------------------------------------------------------------------
void *m_malloc_gbl(ptu32_t size,uint32_t timeout)
{
    uint8_t *ua_address;
    ufast_t  uf_grade_th;
    uint16_t    *pl_id;
    bool_t   en_scheduler;
    void *result;

    if(tg_mem_global.dynamic==false)
        return(__m_static_malloc(size));  //内存尚未初始化,执行准静态内存分配
     //不能在此直接判断size是否满足,因为关取得互斥量前可能发生切换而判断无效.
        if(mutex_pend(&tg_mem_mutex,timeout) == false)
            return NULL;
        en_scheduler = y_query_sch();
    if((tg_mem_global.ua_free_block_max < size)
                && ((timeout == 0) || !en_scheduler))
    {
        result = NULL;
    }else
    {
        if( ! __m_check_memory(size,timeout))
        {
            result = NULL;
        }else
        {
            uf_grade_th=__m_get_grade(size);          //取阶号
            ua_address=__malloc_block(uf_grade_th); //申请内存

            //以下在id表中记录本次分配的性质
            //阅读本段代码请结合mem_global_t中index_event_id成员定义的注释.
            pl_id = &tg_mem_global.index_event_id
                    [(ptu32_t)(ua_address-tg_mem_global.heap_bottom)
                            >>cn_page_size_suffix_zero];
            if(0==uf_grade_th)
                *pl_id = -3;
            else
            {
                *pl_id++ = -4;
                *pl_id = uf_grade_th;
            }
            result = ua_address;
        }
    }
    mutex_post(&tg_mem_mutex);
    return result;
}

//----分配1块内存--------------------------------------------------------------
//功能: 从内存堆中分配一个内存块,内部调用,不开放给用户
//参数: grade,欲分配的块的阶号,0=1阶,1=2阶,类推之
//返回: 获得的内存块指针,如果不能分配则返回NULL
//-----------------------------------------------------------------------------
void *__malloc_block(ufast_t grade)
{
    ptu32_t ua_temp1;
    ptu32_t ua_pages_number;
    ufast_t uf_word_shift,uf_grade_th,uf_classes;
    ufast_t *pl_classes;
    ucpu_t  ***pppl_bitmap;
    ucpu_t  **ppl_bitmap;
    ucpu_t  *pl_bitmap;

    ptu32_t ua_word_offset,ua_bit_num;
    ucpu_t  uc_msk;               //字内偏移量

    pppl_bitmap=tg_mem_global.ppp_bitmap; //空闲金字塔位图指针的指针表的首指针
    ppl_bitmap=pppl_bitmap[grade];        //该阶空闲金字塔位图指针表的首址
    pl_classes=tg_mem_global.p_classes;   //读取各阶空闲金字塔级数表指针.
    uf_classes=pl_classes[grade]-1;       //该阶空闲金字塔最高一级指针在
                                          //ppl_bitmap中的偏移量
    tg_mem_global.free_pages_num -= (1<<grade); //剩余可用页数
    ua_pages_number=0;
    do
    {//本循环查找第一个可分配块(即bit=0)的偏移位数,从高到低查找,方法:
     //首先,找出该阶空闲位图金字塔最高级位图中第一个bit=0的位偏移量.
     //然后,根据这个偏移量计算次高级含0位的字偏移,读出该字并找出bit=0的位偏移.
     //如此反复可以找到最后一级第一个0位的偏移,这就是本次分配的目标块.

        pl_bitmap=ppl_bitmap[uf_classes];   //读取各级位图的指针

        //ua_pages_number是上一级的位偏移,ua_temp1是本级最后一字的字内位偏移
        ua_temp1=cn_cpu_bits-1-__m_leading_ucpu_zero(~pl_bitmap[ua_pages_number]);

        //上一级的字偏移×字长+本级字内位偏移得到本级总位偏移
        ua_pages_number =(ua_pages_number<<cn_cpu_bits_suffix_zero)+ua_temp1;
    }while(uf_classes-- >0);

    ua_pages_number <<= grade;  //目标块的首页的页号

    //下面开始在bitmap表标记本次分配情况
    for(uf_grade_th=0;uf_grade_th<=grade;uf_grade_th++)
    {//从0阶直到当前阶(不包含),处理阶号低于当次申请的内存的位图.
        //块的起始页号右移阶号即得到在该阶0级位图中的偏移
        ua_word_offset = ua_pages_number>>uf_grade_th;
        ppl_bitmap=pppl_bitmap[uf_grade_th];    //取得该阶分配表指针表的首址
        ua_bit_num=1<<(grade-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保存的是需要置1的位
            {//位数大于或等于1个字宽,因为采用2的n次方分阶,所以要处理的位数肯定
             //是整数个字,按整数个字置1就可以了.

                //计算字数,也是下一级位图中需置1的位数
                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]=cn_allbit_1;
            }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] == cn_allbit_1)
                //被置1的位所在的字变为全1时,该字对应的下一级位图相应的位需置1
                    ua_bit_num=0;
                else
                    break;
            }else
            {//前一次操作使一个字从非全1变成全1,置位该字对应的下一级路径相应位
                pl_bitmap[ua_word_offset] |= 1<<uf_word_shift;
                if(pl_bitmap[ua_word_offset] == cn_allbit_1)
                //被置1的位所在的字变为全1时,该字对应的下一级位图相应的位需置1
                    ;
                else
                    break;
            }
        }
    }

    for(; uf_grade_th < tg_mem_global.uf_grades; uf_grade_th++)
    {//当前阶(包含)到最高阶,处理阶号高于或等于当次申请的内存的位图.每次只需1位置1

        //块的起始页号右移阶号即得到在该阶0级位图中的偏移
        ua_word_offset = ua_pages_number >> 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] == cn_allbit_1)
            //被掩模的位所在的字变为全1时,该字对应的下一级位图相应的位需置1
                ;
            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阶

    return tg_mem_global.heap_bottom
                    +(ua_pages_number<<cn_page_size_suffix_zero);
}

//----查询内存尺寸-------------------------------------------------------------
//功能: 根据给定的指针,查询该指针所在的内存块的尺寸.
//参数: mp,动态分配的内存指针.
//返回: 内存块尺寸,返回0有几种含义:1.非法指针,2.mp是由准静态分配的指针.
//----------------------------------------------------------------------------
ptu32_t m_check_size(void * mp)
{
    ptu32_t ua_pages_number;
    uint8_t *temp;
    uint16_t *pl_id;
    ufast_t uf_free_grade_th;
    if(((uint8_t*)mp<tg_mem_global.static_bottom)
                || ((uint8_t*)mp>=tg_mem_global.heap_top))
    {
        return 0;   //错误,指针不在堆范围内
    }

    if((uint8_t*)mp < tg_mem_global.heap_bottom)    //该指针在静态分配区
    {
        temp = (uint8_t*)((uint8_t*)mp - sizeof(ptu32_t));
        return *(ptu32_t*)temp;
    }else                                           //该指针在块相联动态分配区
    {
        //计算释放的内存的页号
        ua_pages_number=(ptu32_t)((ptu32_t)mp-(ptu32_t)tg_mem_global.heap_bottom)
                            >>cn_page_size_suffix_zero;

        //查找释放的内存块的阶号,从0起计.通过阶号也可以确定内存块的大小.
        //确定内存分配类型,局部分配需要知道拥有该内存的事件id,
        //全局分配无需清除内存分配跟踪表,无需知道拥有该内存的事件id
        pl_id = &tg_mem_global.index_event_id[ua_pages_number];
        switch(pl_id[0])
        {
            case 0xffff :
            {//双页局部分配,-1+id
                uf_free_grade_th = 1;
            }break;
            case 0xfffe :
            {//多页局部分配:-2+id+阶号
                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];

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -