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

📄 mems.c

📁 新一代基于事件的嵌入式操作系统dyos在三星的s3c44b0的arm芯片上的完整移植代码
💻 C
📖 第 1 页 / 共 4 页
字号:
    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 + -