浅析LiteOS源码LOS_MemInit函数(bestfit_little算法)

0x00 前言

根据LiteOS官方文档对内存管理部分的介绍,LiteOS公有3种内存管理算法:

  • 静态:BOX算法
  • 动态:bestfit和bestfit_little算法
    这篇文章分析的是bestfit_little算法的LOS_MemInit函数。

0x01 分析函数

先看官方对函数的介绍

/*****************************************************************************
 Function : LOS_MemInit
 Description : Initialize Dynamic Memory pool
 Input       : pPool    --- Pointer to memory pool
               uwSize  --- Size of memory in bytes to allocate
 Output      : None
 Return      : LOS_OK - Ok, LOS_NOK - Error
*****************************************************************************/

函数作用是初始化动态内存池,接收的两个参数,一个指向内存池的地址和一个是大小;返回值表示初始化是否成功。

LITE_OS_SEC_TEXT_INIT UINT32 LOS_MemInit(VOID *pPool, UINT32 uwSize)
{
    BOOL bRet = TRUE;
    UINTPTR uvIntSave;
#if (LOSCFG_MEM_MUL_POOL == YES)
    VOID *pNext = g_pPoolHead;
    VOID * pCur = g_pPoolHead;
    UINT32 uwPoolEnd;
#endif

    if (!pPool || uwSize <= sizeof(struct LOS_HEAP_MANAGER))
        return LOS_NOK;

    if (!IS_POOL_ALIGNED(pPool, OS_MEM_POOL_BASE_ALIGN))
        return LOS_NOK;

    uvIntSave = LOS_IntLock();

3、4行定义局部变量,第一个变量用来接收调用函数后的返回值,用于判断调用函数是否成功;第二个用来保存中断状态,后面会看到是如何使用这个变量的。
第5行根据LOSCFG_MEM_MUL_POOL这个宏定义新建两个指针变量,初值为内存池起始地址;还有一个整型变量,用来存放内存池结束位置的地址。
11行判断传入参数的合法性。
14行检查传入参数pPool所代表的地址是否4字节对齐。
17行关闭所有中断,把关闭中断前的CPSR寄存器值保存在uvIntSave中。

#if (LOSCFG_MEM_MUL_POOL == YES)
    while (pNext != NULL)
    {
        uwPoolEnd = (UINT32)pNext + ((struct LOS_HEAP_MANAGER *)pNext)->uwSize;
        if ((pPool <= pNext && ((UINT32)pPool + uwSize) > (UINT32)pNext) ||
            ((UINT32)pPool < uwPoolEnd && ((UINT32)pPool + uwSize) >= uwPoolEnd))
        {
            PRINT_ERR("pool [%p, 0x%x) conflict with pool [%p, 0x%x)\n",
                          pPool, (UINT32)pPool + uwSize,
                          pNext, (UINT32)pNext + ((struct LOS_HEAP_MANAGER *)pNext)->uwSize);

            LOS_IntRestore(uvIntSave);
            return LOS_NOK;
        }
        pCur = pNext;
        pNext = ((struct LOS_HEAP_MANAGER *)pNext)->pNextPool;
    }
#endif

第1行判断LOSCFG_MEM_MUL_POOL 宏定义。
第2行,pNext前面赋的初值是内存池的起始地址,第16行在每次while循环中都把这个变量更新为下一个内存池的地址。所以这个while循环的意义就是遍历所有内存池。
第4行,获取当前内存池的结束地址(当前内存池的起始地址+内存池大小)。
第5、6行,判断要分配的内存区域是否合理,我用一张图直观地描述一下:判断要分配的内存区域是否合理
第8、9、10行,打印错误信息.
第12行,恢复之前保存的CPSR寄存器内容。
第13行,直接return错误码。
第15、16行,如果上述错误没有发生,更新指针的位置,继续while循环,检查下一块要分配的内存池地址。

    bRet = osHeapInit(pPool, uwSize);
    if(!bRet)
    {
        LOS_IntRestore(uvIntSave);
        return LOS_NOK;
    }

前摇了那么久,这里终于开始初始化内存池了。
第一行调用函数,传入的参数就是LOS_MemInit这个函数接收的参数,原封不动;返回状态码。
第二行以后,老朋友了,不解释。

#if (LOSCFG_KERNEL_MEM_SLAB == YES)
    if (uwSize >= SLAB_BASIC_NEED_SIZE)//if size of pool is small than size of slab need, don`t init slab
    {
        bRet = osSlabMemInit(pPool);
        if(!bRet)
        {
            LOS_IntRestore(uvIntSave);
            return LOS_NOK;
        }
    }
#endif

对内存块相关的支持,如果LOSCFG_KERNEL_MEM_SLAB有定义,调用osSlabMemInit初始化内存块。

#if (LOSCFG_MEM_MUL_POOL == YES)
    if (g_pPoolHead == NULL)
    {
        g_pPoolHead = pPool;
    }
    else
    {
        ((struct LOS_HEAP_MANAGER *)pCur)->pNextPool = pPool;
    }

    ((struct LOS_HEAP_MANAGER *)pPool)->pNextPool = NULL;
#endif

如果定义了LOSCFG_MEM_MUL_POOL多内存池,这里主要是指针的赋值。

#if ((LOSCFG_PLATFORM_EXC == YES) && (LOSCFG_SAVE_EXC_INFO == YES))
    osMemInfoUpdate(pPool, uwSize, MEM_MANG_MEMORY);
#endif

    LOS_IntRestore(uvIntSave);
    return LOS_OK;
}

配置文件里LOSCFG_PLATFORM_EXCLOSCFG_SAVE_EXC_INFO都打开的话,调用osMemInfoUpdate更新一下内存的信息。
第5行,恢复CPSR寄存器的值。
第6行,函数返回。

0x02 总结

函数主要工作,循环判断分配内存地址的合法性,初始化动态内存池。

  • 18
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值