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_EXC
和LOSCFG_SAVE_EXC_INFO
都打开的话,调用osMemInfoUpdate
更新一下内存的信息。
第5行,恢复CPSR寄存器的值。
第6行,函数返回。
0x02 总结
函数主要工作,循环判断分配内存地址的合法性,初始化动态内存池。