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

📄 memb.c

📁 新一代基于事件的嵌入式操作系统dyos在三星的s3c44b0的arm芯片上的完整移植代码
💻 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 + -