3.1.2.3 函数OsVmPhysLargeAlloc
当执行到这个函数时,说明空闲链表上的单个内存页节点的大小已经不能满足要求,超过了第9个链表上的内存页节点的大小了。⑴处计算需要申请的内存大小。⑵从最大的链表上进行遍历每一个内存页节点。⑶根据每个内存页的开始内存地址,计算需要的内存的结束地址,如果超过内存段的大小,则继续遍历下一个内存页节点。
⑷处此时paStart
表示当前内存页的结束地址,接下来paStart >= paEnd
表示当前内存页的大小满足申请的需求;paStart < seg->start
和paStart >= (seg->start + seg->size)
发生溢出错误,内存页结束地址不在内存段的地址范围内。⑸处表示当前内存页的下一个内存页结构体,如果该结构体不在空闲链表上,则break跳出循环。如果在空闲链表上,表示连续的空闲内存页会拼接起来,满足大内存申请的需要。⑹表示一个或者多个连续的内存页的大小满足申请需求。
STATIC LosVmPage *OsVmPhysLargeAlloc(struct VmPhysSeg *seg, size_t nPages)
{
struct VmFreeList *list = NULL;
LosVmPage *page = NULL;
LosVmPage *tmp = NULL;
PADDR_T paStart;
PADDR_T paEnd;
⑴ size_t size = nPages << PAGE_SHIFT;
⑵ list = &seg->freeList[VM_LIST_ORDER_MAX - 1];
LOS_DL_LIST_FOR_EACH_ENTRY(page, &list->node, LosVmPage, node) {
⑶ paStart = page->physAddr;
paEnd = paStart + size;
if (paEnd > (seg->start + seg->size)) {
continue;
}
for (;;) {
⑷ paStart += PAGE_SIZE << (VM_LIST_ORDER_MAX - 1);
if ((paStart >= paEnd) || (paStart < seg->start) ||
(paStart >= (seg->start + seg->size))) {
break;
}
⑸ tmp = &seg->pageBase[(paStart - seg->start) >> PAGE_SHIFT];
if (tmp->order != (VM_LIST_ORDER_MAX - 1)) {
break;
}
}
⑹ if (paStart >= paEnd) {
return page;
}
}
return NULL;
}
3.1.2.4 函数OsVmPhysFreeListDelUnsafe
和OsVmPhysFreeListAddUnsafe
内部函数OsVmPhysFreeListDelUnsafe
用于从空闲内存页节点链表上删除一个内存页节点,名称中有Unsafe字样,是因为函数体内并没有对链表操作加自旋锁,安全性由外部调用函数保证。⑴处进行校验,确保内存段和空闲链表索引符合要求。⑵处获取内存段和空闲链表,⑶处空闲链表上内存页节点数目减1,并把内存块从空闲链表上删除。⑷处设置内存页的order
索引值为最大值来标记非空闲内存页。
STATIC VOID OsVmPhysFreeListDelUnsafe(LosVmPage *page)
{
struct VmPhysSeg *seg = NULL;
struct VmFreeList *list = NULL;
⑴ if ((page->segID >= VM_PHYS_SEG_MAX) || (page->order >= VM_LIST_ORDER_MAX)) {
LOS_Panic("The page segment id(%u) or order(%u) is invalid\n", page->segID, page->order);
}
⑵ seg = &g_vmPhysSeg[page->segID];
list = &seg->freeList[page->order];
⑶ list->listCnt--;
LOS_ListDelete(&page->node);
⑷ page->order = VM_LIST_ORDER_MAX;
}
和空闲链表上删除对应的函数是空闲链表上插入空闲内存页节点函数OsVmPhysFreeListAddUnsafe
。⑴处更新内存页的要挂载的空闲链表的索引值,然后获取内存页所在的内存段seg
,并获取索引值对应的空闲链表。执行⑵把空闲内存页节点插入到空闲链表并更新节点数目。
STATIC VOID OsVmPhysFreeListAddUnsafe(LosVmPage *page, UINT8 order)
{
struct VmPhysSeg *seg = NULL;
struct VmFreeList *list = NULL;
if (page->segID >= VM_PHYS_SEG_MAX) {
LOS_Panic("The page segment id(%d) is invalid\n", page->segID);
}
⑴ page->order = order;
seg = &g_vmPhysSeg[page->segID];
list = &seg->freeList[order];
⑵ LOS_ListTailInsert(&list->node, &page->node);
list->listCnt++;
}