鸿蒙原生开发——轻内核A核源码分析系列三 物理内存(2)

3.1.2.3 函数OsVmPhysLargeAlloc

当执行到这个函数时,说明空闲链表上的单个内存页节点的大小已经不能满足要求,超过了第9个链表上的内存页节点的大小了。⑴处计算需要申请的内存大小。⑵从最大的链表上进行遍历每一个内存页节点。⑶根据每个内存页的开始内存地址,计算需要的内存的结束地址,如果超过内存段的大小,则继续遍历下一个内存页节点。

⑷处此时paStart表示当前内存页的结束地址,接下来paStart >= paEnd表示当前内存页的大小满足申请的需求;paStart < seg->startpaStart >= (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 函数OsVmPhysFreeListDelUnsafeOsVmPhysFreeListAddUnsafe

内部函数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++;
}

3.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值