注解:最佳适应算法解决了什么问题? 内核是如何实现动态内存的最佳分配的?

    搜索 @note_pic 可查看绘制的全部字符图
    搜索 @note_why 是尚未看明白的地方,有看明白的,请Pull Request完善
    搜索 @note_thinking 是一些的思考和建议
    搜索 @note_#if0 是由第三方项目提供不在内核源码中定义的极为重要结构体,为方便理解而添加的。
    搜索 @note_good 是给源码点赞的地方
上级 b553c5fc
......@@ -4,18 +4,18 @@
---
# **[kernel\_liteos\_a_note](https://gitee.com/weharmony/kernel_liteos_a_note): 鸿蒙内核源码注释中文版**
# **鸿蒙内核源码注释中文版 | 从此走进内核的世界**
[![star](https://gitee.com/weharmony/kernel_liteos_a_note/badge/star.svg?theme=dark)](https://gitee.com/weharmony/kernel_liteos_a_note)[![fork](https://gitee.com/weharmony/kernel_liteos_a_note/badge/fork.svg?theme=dark)](https://gitee.com/weharmony/kernel_liteos_a_note)
## **做了些什么呢?**
**[WeHarmony/kernel\_liteos\_a_note](https://gitee.com/weharmony/kernel_liteos_a_note)** 是在鸿蒙官方开源项目 **[OpenHarmony/kernel\_liteos\_a](https://gitee.com/openharmony/kernel_liteos_a)** 基础上给源码加上中文注解的版本,目前几大核心模块加注已基本完成,**整体加注完成70%**,其余正持续加注完善中...
**[WeHarmony/kernel\_liteos\_a_note](https://gitee.com/weharmony/kernel_liteos_a_note)** 是在鸿蒙官方开源项目 **[OpenHarmony/kernel\_liteos\_a](https://gitee.com/openharmony/kernel_liteos_a)** 基础上给源码加上中文注解的版本,目前几大核心模块加注已基本完成, **整体加注完成70%**, 正持续加注完善中 ...
- ### **为何想给鸿蒙源码加上中文注释**
- ### **为何想给鸿蒙内核源码加上中文注释**
源于大学时阅读linux 2.6 内核痛苦经历,一直有个心愿,如何让更多对内核感兴趣的同学减少阅读时间,加速对计算机系统级的理解,而不至于过早的放弃.但因过程种种,一直没有行动,基本要放弃这件事了. 但 2020/9/10 鸿蒙正式开源,重新激活了多年的心愿,就有那么点一发不可收拾了. :|P
源于大学时阅读linux 2.6 内核痛苦经历,一直有个心愿,如何让更多对内核感兴趣的同学减少阅读时间,加速对计算机系统级的理解,而不至于过早的放弃.但因过程种种,多年一直没有行动,基本要放弃这件事了. 恰逢 2020/9/10 鸿蒙正式开源,重新激活了多年的心愿,就有那么点一发不可收拾了. :|P
- ### **致敬鸿蒙内核开发者**
......@@ -105,7 +105,7 @@
- ### **通过fork及时同步最新注解内容**
注解几乎占用了所有的空闲时间,每天都在更新,每天对内核源码都有新感悟,一行行源码在不断的刷新和拓展对内核知识的认知边界. 对已经关注和fork的同学请及时同步最新的注解内容. 内核知识点体量实在太过巨大,过程会反复修正完善,力求言简意赅,词达本意.肯定会有诸多错漏之处,请多包涵. :)
注解几乎占用了所有的空闲时间,每天都会更新,每天都有新感悟,一行行源码在不断的刷新和拓展对内核知识的认知边界. 对已经关注和fork的同学请及时同步最新的注解内容. 内核知识点体量实在太过巨大,过程会反复修正完善,力求言简意赅,词达本意.肯定会有诸多错漏之处,请多包涵. :)
- ### **新增的zzz目录是干什么的?**
......
......@@ -402,7 +402,7 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_HwiCreate(HWI_HANDLE_T hwiNum, //硬中断句
if (hwiHandler == NULL) {//中断处理函数不能为NULL
return OS_ERRNO_HWI_PROC_FUNC_NULL;
}
if ((hwiNum > OS_USER_HWI_MAX) || ((INT32)hwiNum < OS_USER_HWI_MIN)) {//中断数区间限制
if ((hwiNum > OS_USER_HWI_MAX) || ((INT32)hwiNum < OS_USER_HWI_MIN)) {//中断数区间限制 [32,96]
return OS_ERRNO_HWI_NUM_INVALID;
}
......
......@@ -49,13 +49,13 @@ extern "C" {
/**
* @ingroup los_hwi
* Count of interrupts.
*/
*/ //中断次数,每个CPU都会记录响应中断的次数
extern size_t g_intCount[];
/**
* @ingroup los_hwi
* An interrupt is active.
*/
*/ //中断处于活动状态
#define OS_INT_ACTIVE ({ \
size_t intCount; \
UINT32 intSave_ = LOS_IntLock(); \
......@@ -67,25 +67,25 @@ extern size_t g_intCount[];
/**
* @ingroup los_hwi
* An interrupt is inactive.
*/
*/ //中断处于非活动状态
#define OS_INT_INACTIVE (!(OS_INT_ACTIVE))
/**
* @ingroup los_hwi
* Highest priority of a hardware interrupt.
*/
*/ //硬件中断的最高优先级
#define OS_HWI_PRIO_HIGHEST 0
/**
* @ingroup los_hwi
* Lowest priority of a hardware interrupt.
*/
*/ //硬件中断的最低优先级
#define OS_HWI_PRIO_LOWEST 31
/**
* @ingroup los_hwi
* Max name length of a hardware interrupt.
*/
*/ //硬件中断的最大名称长度
#define OS_HWI_MAX_NAMELEN 10
/**
......
......@@ -61,10 +61,15 @@
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
//并发(Concurrent):多个线程在单个核心运行,同一时间一个线程运行,系统不停切换线程,看起来像同时运行,实际上是线程不停切换
//并行(Parallel)每个线程分配给独立的CPU核心,线程同时运行
//单核CPU多个进程或多个线程内能实现并发(微观上的串行,宏观上的并行);多核CPU线程间可以实现宏观和微观上的并行
//LITE_OS_SEC_BSS 和 LITE_OS_SEC_DATA_INIT 是告诉编译器这些全局变量放在哪个数据段
/******************************************************************************
并发(Concurrent):多个线程在单个核心运行,同一时间一个线程运行,系统不停切换线程,
看起来像同时运行,实际上是线程不停切换
并行(Parallel)每个线程分配给独立的CPU核心,线程同时运行
单核CPU多个进程或多个线程内能实现并发(微观上的串行,宏观上的并行)
多核CPU线程间可以实现宏观和微观上的并行
LITE_OS_SEC_BSS 和 LITE_OS_SEC_DATA_INIT 是告诉编译器这些全局变量放在哪个数据段
******************************************************************************/
LITE_OS_SEC_BSS LosProcessCB *g_runProcess[LOSCFG_KERNEL_CORE_NUM];// CPU内核个数,超过一个就实现了并行
LITE_OS_SEC_BSS LosProcessCB *g_processCBArray = NULL; // 进程池数组
LITE_OS_SEC_DATA_INIT STATIC LOS_DL_LIST g_freeProcess;// 空闲状态下的进程链表, .个人觉得应该取名为 g_freeProcessList @note_thinking
......@@ -78,9 +83,9 @@ LITE_OS_SEC_BSS ProcessGroup *g_processGroup = NULL;// 全局进程组,负责管
LITE_OS_SEC_TEXT_INIT VOID OsTaskSchedQueueDequeue(LosTaskCB *taskCB, UINT16 status)
{
LosProcessCB *processCB = OS_PCB_FROM_PID(taskCB->processID);//从进程池中取进程
if (taskCB->taskStatus & OS_TASK_STATUS_READY) {//判断task是否是就绪状态
OS_TASK_PRI_QUEUE_DEQUEUE(processCB, taskCB);//从进程就绪队列中删除
taskCB->taskStatus &= ~OS_TASK_STATUS_READY;//置task为非就绪状态
if (taskCB->taskStatus & OS_TASK_STATUS_READY) { //判断task是否是就绪状态
OS_TASK_PRI_QUEUE_DEQUEUE(processCB, taskCB); //从进程就绪队列中删除
taskCB->taskStatus &= ~OS_TASK_STATUS_READY; //给task贴上非就绪状态标签
}
if (processCB->threadScheduleMap != 0) {//判断所属进程是否还有就绪状态的task
......
......@@ -218,30 +218,36 @@ STATIC VOID OsMemNodeSave(LosMemDynNode *node);
#define OS_MEM_ALIGN(p, alignSize) (((UINTPTR)(p) + (alignSize) - 1) & ~((UINTPTR)((alignSize) - 1)))
#define OS_MEM_NODE_HEAD_SIZE sizeof(LosMemDynNode) //内存池第三部分 一个节点的大小
#define OS_MEM_MIN_POOL_SIZE (OS_DLNK_HEAD_SIZE + (2 * OS_MEM_NODE_HEAD_SIZE) + sizeof(LosMemPoolInfo))
/******************************************************************************
一个内存池最低内存大小是多少呢? 可以算出固定值,
第一部分: sizeof(LosMemPoolInfo)
第二部分: OS_DLNK_HEAD_SIZE
第三部分: 至少需要头尾两个节点 (2 * OS_MEM_NODE_HEAD_SIZE)
******************************************************************************/
#define OS_MEM_MIN_POOL_SIZE (OS_DLNK_HEAD_SIZE + (2 * OS_MEM_NODE_HEAD_SIZE) + sizeof(LosMemPoolInfo))//成为一个内存池最低配置
#define IS_POW_TWO(value) ((((UINTPTR)(value)) & ((UINTPTR)(value) - 1)) == 0)
#define POOL_ADDR_ALIGNSIZE 64
#ifdef LOSCFG_AARCH64
#define OS_MEM_ALIGN_SIZE 8
#define OS_MEM_ALIGN_SIZE 8 //8字节对齐方式 8*8 = 64
#else
#define OS_MEM_ALIGN_SIZE 4
#define OS_MEM_ALIGN_SIZE 4 //4字节对齐方式 4*8 = 64
#endif
#define OS_MEM_NODE_USED_FLAG 0x80000000U
#define OS_MEM_NODE_ALIGNED_FLAG 0x40000000U
#define OS_MEM_NODE_ALIGNED_AND_USED_FLAG (OS_MEM_NODE_USED_FLAG | OS_MEM_NODE_ALIGNED_FLAG)
#define OS_MEM_NODE_ALIGNED_AND_USED_FLAG (OS_MEM_NODE_USED_FLAG | OS_MEM_NODE_ALIGNED_FLAG) //0xB0000000U
#define OS_MEM_NODE_GET_ALIGNED_FLAG(sizeAndFlag) \
((sizeAndFlag) & OS_MEM_NODE_ALIGNED_FLAG)
((sizeAndFlag) & OS_MEM_NODE_ALIGNED_FLAG) //获取对齐标签
#define OS_MEM_NODE_SET_ALIGNED_FLAG(sizeAndFlag) \
((sizeAndFlag) = ((sizeAndFlag) | OS_MEM_NODE_ALIGNED_FLAG))
((sizeAndFlag) = ((sizeAndFlag) | OS_MEM_NODE_ALIGNED_FLAG)) //设置对齐标签
#define OS_MEM_NODE_GET_ALIGNED_GAPSIZE(sizeAndFlag) \
((sizeAndFlag) & ~OS_MEM_NODE_ALIGNED_FLAG)
((sizeAndFlag) & ~OS_MEM_NODE_ALIGNED_FLAG) //通过增加Gap域确保返回的指针符合对齐要求
#define OS_MEM_NODE_GET_USED_FLAG(sizeAndFlag) \
((sizeAndFlag) & OS_MEM_NODE_USED_FLAG)
((sizeAndFlag) & OS_MEM_NODE_USED_FLAG) //获取使用标签
#define OS_MEM_NODE_SET_USED_FLAG(sizeAndFlag) \
((sizeAndFlag) = ((sizeAndFlag) | OS_MEM_NODE_USED_FLAG))
((sizeAndFlag) = ((sizeAndFlag) | OS_MEM_NODE_USED_FLAG)) //设置使用标签
#define OS_MEM_NODE_GET_SIZE(sizeAndFlag) \
((sizeAndFlag) & ~OS_MEM_NODE_ALIGNED_AND_USED_FLAG)
((sizeAndFlag) & ~OS_MEM_NODE_ALIGNED_AND_USED_FLAG) //获得大小
#define OS_MEM_HEAD(pool, size) \
OsDLnkMultiHead(OS_MEM_HEAD_ADDR(pool), size) //通过size找到链表头节点
#define OS_MEM_HEAD_ADDR(pool) \
......@@ -249,13 +255,13 @@ STATIC VOID OsMemNodeSave(LosMemDynNode *node);
#define OS_MEM_NEXT_NODE(node) \
((LosMemDynNode *)(VOID *)((UINT8 *)(node) + OS_MEM_NODE_GET_SIZE((node)->selfNode.sizeAndFlag)))//获取节点的下一个节点
#define OS_MEM_FIRST_NODE(pool) \
((LosMemDynNode *)(VOID *)((UINT8 *)OS_MEM_HEAD_ADDR(pool) + OS_DLNK_HEAD_SIZE)) //指向内存池的第三部分
((LosMemDynNode *)(VOID *)((UINT8 *)OS_MEM_HEAD_ADDR(pool) + OS_DLNK_HEAD_SIZE)) //指向内存池的第三部分的头节点
#define OS_MEM_END_NODE(pool, size) \
((LosMemDynNode *)(VOID *)(((UINT8 *)(pool) + (size)) - OS_MEM_NODE_HEAD_SIZE)) //指向内存池的第三部分的最后一个节点
#define OS_MEM_MIDDLE_ADDR_OPEN_END(startAddr, middleAddr, endAddr) \
(((UINT8 *)(startAddr) <= (UINT8 *)(middleAddr)) && ((UINT8 *)(middleAddr) < (UINT8 *)(endAddr)))
(((UINT8 *)(startAddr) <= (UINT8 *)(middleAddr)) && ((UINT8 *)(middleAddr) < (UINT8 *)(endAddr))) //判断是否为中间地址,只包括等于开始地址
#define OS_MEM_MIDDLE_ADDR(startAddr, middleAddr, endAddr) \
(((UINT8 *)(startAddr) <= (UINT8 *)(middleAddr)) && ((UINT8 *)(middleAddr) <= (UINT8 *)(endAddr)))
(((UINT8 *)(startAddr) <= (UINT8 *)(middleAddr)) && ((UINT8 *)(middleAddr) <= (UINT8 *)(endAddr))) //判断是否为中间地址,包括等于开始和末尾地址
#define OS_MEM_SET_MAGIC(value) \
(value) = (LOS_DL_LIST *)(((UINTPTR)&(value)) ^ (UINTPTR)(-1)) //设置魔法数字
#define OS_MEM_MAGIC_VALID(value) \
......@@ -285,7 +291,7 @@ const VOID *OsMemFindNodeCtrl(const VOID *pool, const VOID *ptr);
(ctlNode)->gapSize ^ \
(ctlNode)->sizeAndFlag ^ \
CHECKSUM_MAGICNUM)
//打印节点信息
STATIC INLINE VOID OsMemDispCtlNode(const LosMemCtlNode *ctlNode)
{
UINTPTR checksum;
......@@ -793,20 +799,20 @@ STATIC INLINE VOID OsMemLinkRegisterRecord(LosMemDynNode *node)
* allocSize --- Size of memory in bytes which note need allocate
* Return : NULL --- no suitable block found
* tmpNode --- pointer a suitable free block
*/
*/ //使用最佳适应算法从内存池中找到空闲节点
STATIC INLINE LosMemDynNode *OsMemFindSuitableFreeBlock(VOID *pool, UINT32 allocSize)
{
LOS_DL_LIST *listNodeHead = NULL;
LosMemDynNode *tmpNode = NULL;
UINT32 maxCount = (LOS_MemPoolSizeGet(pool) / allocSize) << 1;
UINT32 maxCount = (LOS_MemPoolSizeGet(pool) / allocSize) << 1;//循环退出条件
UINT32 count;
#ifdef LOSCFG_MEM_HEAD_BACKUP
UINT32 ret = LOS_OK;
#endif
for (listNodeHead = OS_MEM_HEAD(pool, allocSize); listNodeHead != NULL;
listNodeHead = OsDLnkNextMultiHead(OS_MEM_HEAD_ADDR(pool), listNodeHead)) {
for (listNodeHead = OS_MEM_HEAD(pool, allocSize); listNodeHead != NULL;//从最匹配自身链表一直开始找,自身链表不满足时找下一级链表
listNodeHead = OsDLnkNextMultiHead(OS_MEM_HEAD_ADDR(pool), listNodeHead)) {//因为下一级的内存块比匹配自身链表要大
count = 0;
LOS_DL_LIST_FOR_EACH_ENTRY(tmpNode, listNodeHead, LosMemDynNode, selfNode.freeNodeInfo) {
LOS_DL_LIST_FOR_EACH_ENTRY(tmpNode, listNodeHead, LosMemDynNode, selfNode.freeNodeInfo) {//遍历链表
if (count++ >= maxCount) {
PRINT_ERR("[%s:%d]node: execute too much time\n", __FUNCTION__, __LINE__);
break;
......@@ -829,7 +835,7 @@ STATIC INLINE LosMemDynNode *OsMemFindSuitableFreeBlock(VOID *pool, UINT32 alloc
__FUNCTION__, __LINE__, OS_MEM_HEAD_ADDR(pool), listNodeHead, allocSize, tmpNode);
break;
}
if (tmpNode->selfNode.sizeAndFlag >= allocSize) {
if (tmpNode->selfNode.sizeAndFlag >= allocSize) {//找到节点
return tmpNode;
}
}
......@@ -841,7 +847,7 @@ STATIC INLINE LosMemDynNode *OsMemFindSuitableFreeBlock(VOID *pool, UINT32 alloc
/*
* Description : clear a mem node, set every member to NULL
* Input : node --- Pointer to the mem node which will be cleared up
*/
*/ //清空指定动态内存节点
STATIC INLINE VOID OsMemClearNode(LosMemDynNode *node)
{
(VOID)memset_s((VOID *)node, sizeof(LosMemDynNode), 0, sizeof(LosMemDynNode));
......@@ -850,7 +856,7 @@ STATIC INLINE VOID OsMemClearNode(LosMemDynNode *node)
/*
* Description : merge this node and pre node, then clear this node info
* Input : node --- Pointer to node which will be merged
*/
*/ //合并指定动态内存节点
STATIC INLINE VOID OsMemMergeNode(LosMemDynNode *node)
{
LosMemDynNode *nextNode = NULL;
......@@ -864,7 +870,7 @@ STATIC INLINE VOID OsMemMergeNode(LosMemDynNode *node)
#endif
OsMemClearNode(node);
}
//是否是一个扩展内存池
STATIC INLINE BOOL IsExpandPoolNode(VOID *pool, LosMemDynNode *node)
{
UINTPTR start = (UINTPTR)pool;
......@@ -879,7 +885,7 @@ STATIC INLINE BOOL IsExpandPoolNode(VOID *pool, LosMemDynNode *node)
* After pick up it's node info, change to point the new node
* allocSize -- the size of new node
* Output : allocNode -- save new node addr
*/
*/ //从allocNode拆分新节点,必要时合并剩余的内存
STATIC INLINE VOID OsMemSplitNode(VOID *pool,
LosMemDynNode *allocNode, UINT32 allocSize)
{
......@@ -918,7 +924,7 @@ STATIC INLINE VOID OsMemSplitNode(VOID *pool,
STATIC INLINE LosMemDynNode *PreSentinelNodeGet(const VOID *pool, const LosMemDynNode *node);
STATIC INLINE BOOL OsMemIsLastSentinelNode(LosMemDynNode *node);
//释放大节点内存块,方法是直接释放物理内存
UINT32 OsMemLargeNodeFree(const VOID *ptr)
{
LosVmPage *page = OsVmVaddrToPage((VOID *)ptr);
......@@ -929,7 +935,7 @@ UINT32 OsMemLargeNodeFree(const VOID *ptr)
return LOS_OK;
}
//尝试缩小内存池
STATIC INLINE BOOL TryShrinkPool(const VOID *pool, const LosMemDynNode *node)
{
LosMemDynNode *mySentinel = NULL;
......@@ -967,7 +973,7 @@ STATIC INLINE BOOL TryShrinkPool(const VOID *pool, const LosMemDynNode *node)
* at last update "listNodeHead' which saved all free node control head
* Input : node -- the node which need be freed
* pool -- Pointer to memory pool
*/
*/ //从内存中释放节点,如果旁边有空闲节点,则合并它们,最后更新listNodeHead,它保存了所有空闲节点控制头
STATIC INLINE VOID OsMemFreeNode(LosMemDynNode *node, VOID *pool)
{
LosMemDynNode *preNode = NULL;
......@@ -1118,7 +1124,7 @@ STATIC INLINE BOOL OsMemIsLastSentinelNode(LosMemDynNode *node)
return FALSE;
}
}
//将指定节点设置有哨兵节点
STATIC INLINE VOID OsMemSentinelNodeSet(LosMemDynNode *sentinelNode, VOID *newNode, UINT32 size)
{
if (sentinelNode->selfNode.freeNodeInfo.pstNext != NULL) {
......@@ -1289,12 +1295,12 @@ STATIC INLINE UINT32 OsMemCheckUsedNode(const VOID *pool, const LosMemDynNode *n
/*
* Description : set magic & taskid
* Input : node -- the node which will be set magic & taskid
*/
*/ //给指定节点设置魔法数字和任务ID
STATIC INLINE VOID OsMemSetMagicNumAndTaskID(LosMemDynNode *node)
{
LosTaskCB *runTask = OsCurrTaskGet();
OS_MEM_SET_MAGIC(node->selfNode.freeNodeInfo.pstPrev);
OS_MEM_SET_MAGIC(node->selfNode.freeNodeInfo.pstPrev);//通过pstPrev生成魔法数字也是挺赞的! @note_good
/*
* If the operation occured before task initialization(runTask was not assigned)
......@@ -1478,7 +1484,7 @@ STATIC VOID OsMemNodeBacktraceInfo(const LosMemDynNode *tmpNode,
#endif
}
#endif
//打印节点信息
STATIC VOID OsMemNodeInfo(const LosMemDynNode *tmpNode,
const LosMemDynNode *preNode)
{
......@@ -1613,7 +1619,7 @@ STATIC INLINE INT32 OsMemPoolExpand(VOID *pool, UINT32 size, UINT32 intSave)
LOS_DL_LIST *listNodeHead = NULL;
size = ROUNDUP(size + OS_MEM_NODE_HEAD_SIZE, PAGE_SIZE);
endNode = (LosMemDynNode *)OS_MEM_END_NODE(pool, poolInfo->poolSize);
endNode = (LosMemDynNode *)OS_MEM_END_NODE(pool, poolInfo->poolSize);//获取内存池的尾部节点
RETRY:
newNode = (LosMemDynNode *)LOS_PhysPagesAllocContiguous(size >> PAGE_SHIFT);//分配连续的物理内存
......@@ -1664,7 +1670,7 @@ VOID LOS_MemExpandEnable(VOID *pool)
((LosMemPoolInfo *)pool)->flag = MEM_POOL_EXPAND_ENABLE;
}
#ifdef LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK
#ifdef LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK //内存节点完整性检查开关
STATIC INLINE UINT32 OsMemAllocCheck(VOID *pool, UINT32 intSave)
{
......@@ -1691,7 +1697,7 @@ STATIC INLINE UINT32 OsMemAllocCheck(VOID *pool, UINT32 intSave)
* Input : pool --- Pointer to memory pool
* size --- Size of memory in bytes to allocate
* Return : Pointer to allocated memory
*/
*/ //从内存池分配节点
STATIC INLINE VOID *OsMemAllocWithCheck(VOID *pool, UINT32 size, UINT32 intSave)
{
LosMemDynNode *allocNode = NULL;
......@@ -1700,28 +1706,28 @@ STATIC INLINE VOID *OsMemAllocWithCheck(VOID *pool, UINT32 size, UINT32 intSave)
const VOID *firstNode = (const VOID *)((UINT8 *)OS_MEM_HEAD_ADDR(pool) + OS_DLNK_HEAD_SIZE);
INT32 ret;
if (OsMemAllocCheck(pool, intSave) == LOS_NOK) {
if (OsMemAllocCheck(pool, intSave) == LOS_NOK) {//检查内存池的完整性
return NULL;
}
allocSize = OS_MEM_ALIGN(size + OS_MEM_NODE_HEAD_SIZE, OS_MEM_ALIGN_SIZE);
if (allocSize == 0) {
if (allocSize == 0) {//检查对齐
return NULL;
}
retry:
allocNode = OsMemFindSuitableFreeBlock(pool, allocSize);//从内存池中找到合适的内存块
if (allocNode == NULL) {
if (poolInfo->flag & MEM_POOL_EXPAND_ENABLE) {
ret = OsMemPoolExpand(pool, allocSize, intSave);//木有找到就扩展内存池
if (ret == 0) {
goto retry;
allocNode = OsMemFindSuitableFreeBlock(pool, allocSize);//从内存池中找到合适的节点
if (allocNode == NULL) {//内存池中没有找到合适的节点
if (poolInfo->flag & MEM_POOL_EXPAND_ENABLE) {//内存池是否允许扩展
ret = OsMemPoolExpand(pool, allocSize, intSave);//扩大内存池
if (ret == 0) {//扩大成功了
goto retry; // 注意这个goto语句,回去再找合适的节点
}
}
PRINT_ERR("---------------------------------------------------"
"--------------------------------------------------------\n");
MEM_UNLOCK(intSave);
OsMemInfoPrint(pool);
OsMemInfoPrint(pool);//打印内存池的信息
MEM_LOCK(intSave);
PRINT_ERR("[%s] No suitable free block, require free node size: 0x%x\n", __FUNCTION__, allocSize);
PRINT_ERR("----------------------------------------------------"
......@@ -1729,11 +1735,11 @@ retry:
return NULL;
}
if ((allocSize + OS_MEM_NODE_HEAD_SIZE + OS_MEM_ALIGN_SIZE) <= allocNode->selfNode.sizeAndFlag) {
OsMemSplitNode(pool, allocNode, allocSize);//找到了就劈开node
OsMemSplitNode(pool, allocNode, allocSize);//用不了那么多内存的情况劈开node
}
OsMemListDelete(&allocNode->selfNode.freeNodeInfo, firstNode);//从空闲链表中删除该节点
OsMemSetMagicNumAndTaskID(allocNode);
OS_MEM_NODE_SET_USED_FLAG(allocNode->selfNode.sizeAndFlag);
OsMemListDelete(&allocNode->selfNode.freeNodeInfo, firstNode);//从空闲链表中删除该节点
OsMemSetMagicNumAndTaskID(allocNode);//设置魔法数字和任务ID
OS_MEM_NODE_SET_USED_FLAG(allocNode->selfNode.sizeAndFlag);//贴上节点已使用的标签
if ((pool == (VOID *)OS_SYS_MEM_ADDR) || (pool == (VOID *)m_aucSysMem0)) {
OS_MEM_ADD_USED(OS_MEM_NODE_GET_SIZE(allocNode->selfNode.sizeAndFlag), OS_MEM_TASKID_GET(allocNode));
}
......@@ -1851,24 +1857,24 @@ STATIC UINT32 OsMemInit(VOID *pool, UINT32 size)
LosMemDynNode *endNode = NULL;
LOS_DL_LIST *listNodeHead = NULL;
poolInfo->pool = pool; //内存池开始地址,这里决定了 pool 变量一定要放在结构体的首位
poolInfo->poolSize = size; //内存池大小
poolInfo->pool = pool; //保存内存池开始地址,这里决定了 pool 变量一定要放在结构体的首位
poolInfo->poolSize = size; //保证内存池大小
poolInfo->flag = MEM_POOL_EXPAND_DISABLE;//内存池默认不能扩展
OsDLnkInitMultiHead(OS_MEM_HEAD_ADDR(pool));//初始化内存池的第二部分(双向链表部分)
newNode = OS_MEM_FIRST_NODE(pool);
newNode->selfNode.sizeAndFlag = (size - (UINT32)((UINTPTR)newNode - (UINTPTR)pool) - OS_MEM_NODE_HEAD_SIZE);
newNode->selfNode.preNode = (LosMemDynNode *)OS_MEM_END_NODE(pool, size);
listNodeHead = OS_MEM_HEAD(pool, newNode->selfNode.sizeAndFlag);
if (listNodeHead == NULL) {
newNode = OS_MEM_FIRST_NODE(pool);//跳到内存池第三部分(动态节点部分)
newNode->selfNode.sizeAndFlag = (size - (UINT32)((UINTPTR)newNode - (UINTPTR)pool) - OS_MEM_NODE_HEAD_SIZE);//得到内存池剩余的大小
newNode->selfNode.preNode = (LosMemDynNode *)OS_MEM_END_NODE(pool, size);//首个节点指向最后一个节点
listNodeHead = OS_MEM_HEAD(pool, newNode->selfNode.sizeAndFlag);//通过节点大小,找到节点在内存池第二部分对应的链表头
if (listNodeHead == NULL) {//只有一种情况,给的内存池太大了,大于 2^30, 无法管理
return LOS_NOK;
}
LOS_ListTailInsert(listNodeHead, &(newNode->selfNode.freeNodeInfo));
endNode = (LosMemDynNode *)OS_MEM_END_NODE(pool, size);
(VOID)memset_s(endNode, sizeof(*endNode), 0, sizeof(*endNode));
LOS_ListTailInsert(listNodeHead, &(newNode->selfNode.freeNodeInfo));//将首个节点挂入对应的链表
endNode = (LosMemDynNode *)OS_MEM_END_NODE(pool, size);//取出尾部节点
(VOID)memset_s(endNode, sizeof(*endNode), 0, sizeof(*endNode));//清空尾部节点
endNode->selfNode.preNode = newNode;
OsMemSentinelNodeSet(endNode, NULL, 0);
endNode->selfNode.preNode = newNode;//尾部节点的前一个节点为首个节点
OsMemSentinelNodeSet(endNode, NULL, 0);//将尾部节点设置为哨兵节点
#if defined(OS_MEM_WATERLINE) && (OS_MEM_WATERLINE == YES)
poolInfo->poolCurUsedSize = sizeof(LosMemPoolInfo) + OS_MULTI_DLNK_HEAD_SIZE +
OS_MEM_NODE_GET_SIZE(endNode->selfNode.sizeAndFlag);
......@@ -1979,17 +1985,17 @@ LITE_OS_SEC_TEXT VOID *LOS_MemAlloc(VOID *pool, UINT32 size)
VOID *ptr = NULL;
UINT32 intSave;
if ((pool == NULL) || (size == 0)) {
if ((pool == NULL) || (size == 0)) {//不指定内存池和大小时,通常开机时
return (size > 0) ? OsVmBootMemAlloc(size) : NULL;//引导分配器分配,粗暴!
}
MEM_LOCK(intSave);//内存自旋锁
do {
if (OS_MEM_NODE_GET_USED_FLAG(size) || OS_MEM_NODE_GET_ALIGNED_FLAG(size)) {//最大不超过2G,对齐不超过1G
break;
break;//要的太大,申请失败
}
ptr = OsMemAllocWithCheck(pool, size, intSave);//从内存池分配 详见 鸿蒙内核源码分析(内存分配篇)
ptr = OsMemAllocWithCheck(pool, size, intSave);//从内存池分配的主体函数
} while (0);//只执行一次为什么要这么写,这是面试经常考的地方!
#ifdef LOSCFG_MEM_RECORDINFO
......
[鸿蒙内核源码注释中文版 【 Gitee仓 ](https://gitee.com/weharmony/kernel_liteos_a_note) | [ CSDN仓 ](https://codechina.csdn.net/kuangyufei/kernel_liteos_a_note) | [ Github仓 ](https://github.com/kuangyufei/kernel_liteos_a_note) | [ Coding仓 】](https://weharmony.coding.net/public/harmony/kernel_liteos_a_note/git/files) 项目中文注解鸿蒙官方内核源码,图文并茂,详细阐述鸿蒙架构和代码设计细节.每个码农,学职生涯,都应精读一遍内核源码.精读内核源码最大的好处是:将孤立知识点织成一张高浓度,高密度底层网,对计算机底层体系化理解形成永久记忆,从此高屋建瓴分析/解决问题.
[鸿蒙内核源码注释中文版 【 Gitee仓 ](https://gitee.com/weharmony/kernel_liteos_a_note) | [ CSDN仓 ](https://codechina.csdn.net/kuangyufei/kernel_liteos_a_note) | [ Github仓 ](https://github.com/kuangyufei/kernel_liteos_a_note) | [ Coding仓 】](https://weharmony.coding.net/public/harmony/kernel_liteos_a_note/git/files) 项目中文注解鸿蒙官方内核源码,图文并茂,详细阐述鸿蒙架构和代码设计细节.每个码农,学职生涯,都应精读一遍内核源码.最大的好处是:将孤立知识点织成一张高浓度,高密度底层网,对计算机底层体系化理解形成永久记忆,从此高屋建瓴分析/解决问题.
[鸿蒙源码分析系列篇 【 CSDN ](https://blog.csdn.net/kuangyufei/article/details/108727970) [| OSCHINA ](https://my.oschina.net/u/3751245/blog/4626852) [| WIKI 】](https://gitee.com/weharmony/kernel_liteos_a_note/wikis/pages) 从 HarmonyOS 架构层视角整理成文, 并首创用生活场景讲故事的方式试图去解构内核,一窥究竟。
---
## **[kernel\_liteos\_a_note](https://gitee.com/weharmony/kernel_liteos_a_note): 鸿蒙内核源码注释中文版 -> 点击目录和文件查看源码的详细中文注解**
## **[kernel\_liteos\_a_note](https://gitee.com/weharmony/kernel_liteos_a_note): 鸿蒙内核源码注释中文版**
可以肯定是以下问题在一行行的源码中都能找到答案
点击目录和文件查看详细源码中文注解,走进内核的世界.
---
- [kernel_liteos_a_note](https://gitee.com/weharmony/kernel_liteos_a_note/)
* [kernel](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/)
+ [base](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/)
+ [core](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/core/)
+ [core](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/core/) -> []() -> 这个core指的是与CPU core相关的文件
+ [los_bitmap.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/core/los_bitmap.c) -> []() -> 位图管理器有什么作用 ? 在内核常应用于哪些场景 ?
+ [los_process.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/core/los_process.c) -> [鸿蒙内核源码分析(进程管理篇)](https://blog.csdn.net/kuangyufei/article/details/108595941) -> 进程是内核的资源管理单元,它是如何管理 任务, 内存,文件的 ? 进程间是如何协作的 ?
+ [los_sortlink.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/core/los_sortlink.c) -> []() -> 排序链表的实现,它的应用场景是怎样的 ?
......@@ -32,7 +32,15 @@
+ [los_sem.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/ipc/los_sem.c) -> []() -> 信号量解决了什么问题 ? 它的本质是什么 ?
+ [los_sem_debug.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/ipc/los_sem_debug.c) -> []() -> 如何调试信号量 ?
+ [los_signal.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/ipc/los_signal.c) -> []() -> 信号解决了什么问题? 你知道哪些信号 ?
+ [mem](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/mem/) -> []() ->
+ [mem](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/mem/) -> []() -> 内存管理模块管理系统的内存资源,它是操作系统的核心模块之一
+ [bestfit](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/mem/bestfit/) -> []() -> 动态内存管理的优点是按需分配,那缺点又是什么?
+ [los_memory.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/mem/bestfit/los_memory.c) -> []() -> 鸿蒙内核中动态内存池由哪三个部分组成 ?
+ [los_multipledlinkhead.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/mem/bestfit/los_multipledlinkhead.c) -> []() -> 什么是最佳适应算法? 是如何实现 ?
+ [bestfit_little](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/mem/bestfit_little/) -> []() -> bestfit_little算法是在最佳适配算法的基础上加入slab机制形成的算法。
+ [los_heap.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/mem/bestfit/los_heap.c) -> []() -> slab算法机制是怎样的? 又是如何实现的 ?
+ [common](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/mem/common/) -> []() ->
+ [membox](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/mem/membox/) -> []() -> 静态内存池的优点是分配和释放效率高,无碎片, 那缺点呢 ?
+ [los_membox.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/mem/membox/los_membox.c) -> []() -> 静态内存有什么用? 是如何实现的?
+ [misc](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/misc/) -> []() ->
+ [kill_shellcmd.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/misc/kill_shellcmd.c) -> []() -> shell命令kill的实现,熟悉的 kill 9 18 的背后发生了什么?
+ [los_misc.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/misc/los_misc.c) -> []() ->
......@@ -42,9 +50,9 @@
+ [sysinfo_shellcmd.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/misc/sysinfo_shellcmd.c) -> []() -> 和系统信息相关的shell命令有哪些 ?
+ [task_shellcmd.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/misc/task_shellcmd.c) -> []() -> 和任务相关的shell命令有哪些 ?
+ [vm_shellcmd.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/misc/vm_shellcmd.c) -> []() -> 和虚拟内存相关的shell命令有哪些 ?
+ [mp](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/mp/) -> []() ->
+ [mp](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/mp/) -> []() -> MP指支持多处理器的模块
+ [los_lockdep.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/mp/los_lockdep.c) -> []() -> 死锁是怎么发生的 ? 如何检测死锁 ?
+ [los_mp.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/mp/los_mp.c) -> []() -> 鸿蒙支持多CPU吗 ? 它们是如何工作的? CPU之间是如何通讯的 ?
+ [los_mp.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/mp/los_mp.c) -> []() -> 鸿蒙最大支持多少个CPU ? 它们是如何工作的? CPU之间是如何通讯的 ?
+ [los_percpu.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/mp/los_percpu.c) -> []() -> CPU有哪些信息 ?
+ [los_stat.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/mp/los_stat.c) -> []() -> CPU的运行信息如何统计 ?
+ [om](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/base/om/) -> []() ->
......@@ -101,15 +109,7 @@
+ [los_vdso_sys.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/extended/vdso/usr/los_vdso_sys.c) -> []() ->
+ [user/src](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/user/src/) -> []() ->
+ [los_user_init.c](https://gitee.com/weharmony/kernel_liteos_a_note/tree/master/kernel/user/src/los_user_init.c) -> []() ->
---
系列篇文章 进入 >\> [鸿蒙系统源码分析(总目录) 【 CSDN](https://blog.csdn.net/kuangyufei/article/details/108727970) | [OSCHINA](https://my.oschina.net/u/3751245/blog/4626852) [| WIKI 】](https://gitee.com/weharmony/kernel_liteos_a_note/wikis/pages)查看
......
git add -A
git commit -m '注解 动态内存池分成了哪三部分来管理? 代码实现有哪些亮点值得点赞 ?
搜索 @note_pic 方便理解画的字符图
搜索 @note_why 尚未看明白的地方,如果您看明白了,请告知完善
搜索 @note_thinking 一点思考和吐槽的地方
搜索 @note_#if0 由第三方项目提供不由内核源码中定义的极为重要的结构体,为方便理解而添加的
搜索 @note_good 给源码点赞
git commit -m '注解:最佳适应算法解决了什么问题? 内核是如何实现动态内存的最佳分配的?
搜索 @note_pic 可查看绘制的全部字符图
搜索 @note_why 是尚未看明白的地方,有看明白的,请Pull Request完善
搜索 @note_thinking 是一些的思考和建议
搜索 @note_#if0 是由第三方项目提供不在内核源码中定义的极为重要结构体,为方便理解而添加的。
搜索 @note_good 是给源码点赞的地方
'
git push origin master
......
typedef unsigned int UINTPTR;
typedef unsigned char UINT8;
typedef unsigned short UINT16;
......@@ -27,4 +25,15 @@ typedef unsigned long VADDR_T;
typedef struct LOS_DL_LIST {
struct LOS_DL_LIST *pstPrev; /**< Current node's pointer to the previous node */
struct LOS_DL_LIST *pstNext; /**< Current node's pointer to the next node */
} LOS_DL_LIST;
\ No newline at end of file
} LOS_DL_LIST;
//--------------------------------------------------------------------------------------------------------------------
#define HEAP_CAST(t, exp) ((t)(exp))
#define HEAP_ALIGN 4
#define HEAP_TAIL_NODE_SIZE_THRESHOLD 1024
#define ALIGNE(sz) (((sz) + HEAP_ALIGN - 1) & (~(HEAP_ALIGN - 1)))
#define OS_MEM_ALIGN(value, align) (((UINT32)(UINTPTR)(value) + (UINT32)((align) - 1)) & \
(~(UINT32)((align) - 1)))
#define OS_MEM_ALIGN_FLAG 0x80000000
#define OS_MEM_SET_ALIGN_FLAG(align) ((align) = ((align) | OS_MEM_ALIGN_FLAG))
#define OS_MEM_GET_ALIGN_FLAG(align) ((align) & OS_MEM_ALIGN_FLAG)
#define OS_MEM_GET_ALIGN_GAPSIZE(align) ((align) & (~OS_MEM_ALIGN_FLAG))
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册