鴻蒙輕內(nèi)核A核源碼分析系列三 物理內(nèi)存之二
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
3.1.2.3 函數(shù)OsVmPhysLargeAlloc
當執(zhí)行到這個函數(shù)時,說明空閑鏈表上的單個內(nèi)存頁節(jié)點的大小已經(jīng)不能滿足要求,超過了第9個鏈表上的內(nèi)存頁節(jié)點的大小了。⑴處計算需要申請的內(nèi)存大小。⑵從最大的鏈表上進行遍歷每一個內(nèi)存頁節(jié)點。⑶根據(jù)每個內(nèi)存頁的開始內(nèi)存地址,計算需要的內(nèi)存的結(jié)束地址,如果超過內(nèi)存段的大小,則繼續(xù)遍歷下一個內(nèi)存頁節(jié)點。
⑷處此時paStart表示當前內(nèi)存頁的結(jié)束地址,接下來paStart >= paEnd表示當前內(nèi)存頁的大小滿足申請的需求;paStart < seg->start和paStart >= (seg->start + seg->size)發(fā)生溢出錯誤,內(nèi)存頁結(jié)束地址不在內(nèi)存段的地址范圍內(nèi)。⑸處表示當前內(nèi)存頁的下一個內(nèi)存頁結(jié)構(gòu)體,如果該結(jié)構(gòu)體不在空閑鏈表上,則break跳出循環(huán)。如果在空閑鏈表上,表示連續(xù)的空閑內(nèi)存頁會拼接起來,滿足大內(nèi)存申請的需要。⑹表示一個或者多個連續(xù)的內(nèi)存頁的大小滿足申請需求。
- 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 函數(shù)OsVmPhysFreeListDelUnsafe和OsVmPhysFreeListAddUnsafe
內(nèi)部函數(shù)OsVmPhysFreeListDelUnsafe用于從空閑內(nèi)存頁節(jié)點鏈表上刪除一個內(nèi)存頁節(jié)點,名稱中有Unsafe字樣,是因為函數(shù)體內(nèi)并沒有對鏈表操作加自旋鎖,安全性由外部調(diào)用函數(shù)保證。⑴處進行校驗,確保內(nèi)存段和空閑鏈表索引符合要求。⑵處獲取內(nèi)存段和空閑鏈表,⑶處空閑鏈表上內(nèi)存頁節(jié)點數(shù)目減1,并把內(nèi)存塊從空閑鏈表上刪除。⑷處設(shè)置內(nèi)存頁的order索引值為最大值來標記非空閑內(nèi)存頁。
- 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;
- }
和空閑鏈表上刪除對應(yīng)的函數(shù)是空閑鏈表上插入空閑內(nèi)存頁節(jié)點函數(shù)OsVmPhysFreeListAddUnsafe。⑴處更新內(nèi)存頁的要掛載的空閑鏈表的索引值,然后獲取內(nèi)存頁所在的內(nèi)存段seg,并獲取索引值對應(yīng)的空閑鏈表。執(zhí)行⑵把空閑內(nèi)存頁節(jié)點插入到空閑鏈表并更新節(jié)點數(shù)目。
- 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.1.2.5 函數(shù)OsVmPhysPagesSpiltUnsafe
函數(shù)OsVmPhysPagesSpiltUnsafe用于分割內(nèi)存塊,參數(shù)中oldOrder表示需要申請的內(nèi)存頁節(jié)點對應(yīng)的鏈表索引,newOrder表示實際申請的內(nèi)存頁節(jié)點對應(yīng)的鏈表索引。如果索引值相等,則不需要拆分,不會執(zhí)行for循環(huán)塊的代碼。由于伙伴算法中的鏈表數(shù)組中元素的特點,即每個鏈表中的內(nèi)存頁節(jié)點的大小等于2的冪次方個內(nèi)存頁。在拆分時,依次從高索引newOrder往低索引oldOrder遍歷,拆分一個內(nèi)存頁節(jié)點作為空閑內(nèi)存頁節(jié)點掛載到對應(yīng)的空閑鏈表上。⑴處開始循環(huán)從高索引到低索引,索引值減1,然后執(zhí)行⑵獲取伙伴內(nèi)存頁節(jié)點,可以看出,申請的內(nèi)存塊大于需求時,會把后半部分的高地址部分放入空閑鏈表,保留前半部分的低地址部分。⑶處的斷言確?;锇閮?nèi)存頁節(jié)點索引值是最大值,表示屬于空閑內(nèi)存頁節(jié)點。⑷處調(diào)用函數(shù)把內(nèi)存頁節(jié)點放入空閑鏈表。
- STATIC VOID OsVmPhysPagesSpiltUnsafe(LosVmPage *page, UINT8 oldOrder, UINT8 newOrder)
- {
- UINT32 order;
- LosVmPage *buddyPage = NULL;
- for (order = newOrder; order > oldOrder;) {
- ⑴ order--;
- ⑵ buddyPage = &page[VM_ORDER_TO_PAGES(order)];
- ⑶ LOS_ASSERT(buddyPage->order == VM_LIST_ORDER_MAX);
- ⑷ OsVmPhysFreeListAddUnsafe(buddyPage, order);
- }
- }
這里有必要放這一張圖,直觀演示一下。假如我們需要申請8個內(nèi)存頁大小的內(nèi)存節(jié)點,但是只有freeList[7]鏈表上才有空閑節(jié)點。申請成功后,超過了應(yīng)用需要的大小,需要進行拆分。把27個內(nèi)存頁分為2份大小為26個內(nèi)存頁的節(jié)點,第一份繼續(xù)拆分,第二份掛載到freeList[6]鏈表上。然后把第一份26個內(nèi)存頁拆分為2個25個內(nèi)存頁節(jié)點,第一份繼續(xù)拆分,第二份掛載到freeList[5]鏈表上。依次進行下去,最后拆分為2份2^3個內(nèi)存頁大小的內(nèi)存頁節(jié)點,第一份作為實際申請的內(nèi)存頁返回,第二份掛載到freeList[3]鏈表上。如下圖紅色部分所示。

另外,函數(shù)OsVmRecycleExtraPages會調(diào)用OsVmPhysPagesFreeContiguous來回收申請的多余的內(nèi)存頁,后文再分析。
3.2 釋放物理內(nèi)存頁接口
3.2.1 釋放物理內(nèi)存頁接口介紹
和申請物理內(nèi)存頁接口相對應(yīng)著,釋放物理內(nèi)存頁的接口有3個,分別用于滿足不同的釋放內(nèi)存頁需求。函數(shù)LOS_PhysPagesFreeContiguous的傳入?yún)?shù)為要釋放物理頁對應(yīng)的內(nèi)核虛擬地址空間中的虛擬內(nèi)存地址和內(nèi)存頁數(shù)目。⑴處調(diào)用函數(shù)OsVmVaddrToPage把虛擬內(nèi)存地址轉(zhuǎn)換為物理內(nèi)存頁結(jié)構(gòu)體地址,然后⑵處把內(nèi)存頁的連續(xù)內(nèi)存頁數(shù)目設(shè)置為0。⑶處調(diào)用函數(shù)OsVmPhysPagesFreeContiguous()釋放物理內(nèi)存頁。函數(shù)LOS_PhysPageFree用于釋放一個物理內(nèi)存頁,傳入?yún)?shù)為要釋放的物理頁對應(yīng)的物理頁結(jié)構(gòu)體地址。⑷處對引用計數(shù)自減,當小于等于0,表示沒有其他引用時才進一步執(zhí)行釋放操作。該函數(shù)同樣會調(diào)用函數(shù)OsVmPhysPagesFreeContiguous()釋放物理內(nèi)存頁。函數(shù)LOS_PhysPagesFree用于釋放掛在雙向鏈表上的多個物理內(nèi)存頁,返回值為實際釋放的物理頁數(shù)目。⑸處遍歷內(nèi)存頁雙向鏈表,從鏈表上移除要釋放的內(nèi)存頁節(jié)點。⑹處代碼和釋放一個內(nèi)存頁的函數(shù)代碼相同。⑺處計算遍歷的內(nèi)存頁的數(shù)目,函數(shù)最后會返回該值。
- VOID LOS_PhysPagesFreeContiguous(VOID *ptr, size_t nPages)
- {
- UINT32 intSave;
- struct VmPhysSeg *seg = NULL;
- LosVmPage *page = NULL;
- if (ptr == NULL) {
- return;
- }
- ⑴ page = OsVmVaddrToPage(ptr);
- if (page == NULL) {
- VM_ERR("vm page of ptr(%#x) is null", ptr);
- return;
- }
- ⑵ page->nPages = 0;
- seg = &g_vmPhysSeg[page->segID];
- LOS_SpinLockSave(&seg->freeListLock, &intSave);
- ⑶ OsVmPhysPagesFreeContiguous(page, nPages);
- LOS_SpinUnlockRestore(&seg->freeListLock, intSave);
- }
- ......
- VOID LOS_PhysPageFree(LosVmPage *page)
- {
- UINT32 intSave;
- struct VmPhysSeg *seg = NULL;
- if (page == NULL) {
- return;
- }
- ⑷ if (LOS_AtomicDecRet(&page->refCounts) <= 0) {
- seg = &g_vmPhysSeg[page->segID];
- LOS_SpinLockSave(&seg->freeListLock, &intSave);
- OsVmPhysPagesFreeContiguous(page, ONE_PAGE);
- LOS_AtomicSet(&page->refCounts, 0);
- LOS_SpinUnlockRestore(&seg->freeListLock, intSave);
- }
- }
- ······
- size_t LOS_PhysPagesFree(LOS_DL_LIST *list)
- {
- UINT32 intSave;
- LosVmPage *page = NULL;
- LosVmPage *nPage = NULL;
- LosVmPhysSeg *seg = NULL;
- size_t count = 0;
- if (list == NULL) {
- return 0;
- }
- LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(page, nPage, list, LosVmPage, node) {
- ⑸ LOS_ListDelete(&page->node);
- ⑹ if (LOS_AtomicDecRet(&page->refCounts) <= 0) {
- seg = &g_vmPhysSeg[page->segID];
- LOS_SpinLockSave(&seg->freeListLock, &intSave);
- OsVmPhysPagesFreeContiguous(page, ONE_PAGE);
- LOS_AtomicSet(&page->refCounts, 0);
- LOS_SpinUnlockRestore(&seg->freeListLock, intSave);
- }
- ⑺ count++;
- }
- return count;
- }
3.2.2 釋放物理內(nèi)存頁內(nèi)部接口實現(xiàn)
3.2.2.1 函數(shù)OsVmVaddrToPage
函數(shù)OsVmVaddrToPage把虛擬內(nèi)存地址轉(zhuǎn)換為物理頁結(jié)構(gòu)體地址。⑴處調(diào)用函數(shù)LOS_PaddrQuery()把虛擬地址轉(zhuǎn)為物理地址,該函數(shù)在虛實映射部分會詳細講述。⑵處遍歷物理內(nèi)存段,如果物理內(nèi)存地址處于物理內(nèi)存段的地址范圍,則可以返回該物理地址對應(yīng)的物理頁結(jié)構(gòu)體地址。
- LosVmPage *OsVmVaddrToPage(VOID *ptr)
- {
- struct VmPhysSeg *seg = NULL;
- ⑴ PADDR_T pa = LOS_PaddrQuery(ptr);
- UINT32 segID;
- for (segID = 0; segID < g_vmPhysSegNum; segID++) {
- seg = &g_vmPhysSeg[segID];
- ⑵ if ((pa >= seg->start) && (pa < (seg->start + seg->size))) {
- return seg->pageBase + ((pa - seg->start) >> PAGE_SHIFT);
- }
- }
- return NULL;
- }
3.2.2.2 函數(shù)OsVmPhysPagesFreeContiguous
函數(shù)OsVmPhysPagesFreeContiguous()用于釋放指定數(shù)量的連續(xù)物理內(nèi)存頁。⑴處根據(jù)物理內(nèi)存頁獲取對應(yīng)的物理內(nèi)存地址。⑵處根據(jù)物理內(nèi)存地址獲取空閑內(nèi)存頁鏈表數(shù)組索引數(shù)值。⑶處獲取索引值對應(yīng)的鏈表上的內(nèi)存頁節(jié)點的內(nèi)存頁數(shù)目。⑷處如果要釋放的內(nèi)存頁數(shù)nPages小于當前鏈表上的內(nèi)存頁節(jié)點的數(shù)目,則跳出循環(huán)執(zhí)行⑹處代碼,去釋放到小索引的雙向鏈表上。⑸處調(diào)用函數(shù)OsVmPhysPagesFree()釋放指定鏈表上的內(nèi)存頁,然后更新內(nèi)存頁數(shù)量和內(nèi)存頁結(jié)構(gòu)體地址。
⑹處根據(jù)內(nèi)存頁數(shù)量計算對應(yīng)的鏈表索引,根據(jù)索引值計算鏈表上內(nèi)存頁節(jié)點的大小。⑺處調(diào)用函數(shù)OsVmPhysPagesFree()釋放指定鏈表上的內(nèi)存頁,然后更新內(nèi)存頁數(shù)量和內(nèi)存頁結(jié)構(gòu)體地址。
- VOID OsVmPhysPagesFreeContiguous(LosVmPage *page, size_t nPages)
- {
- paddr_t pa;
- UINT32 order;
- size_t n;
- while (TRUE) {
- ⑴ pa = VM_PAGE_TO_PHYS(page);
- ⑵ order = VM_PHYS_TO_ORDER(pa);
- ⑶ n = VM_ORDER_TO_PAGES(order);
- ⑷ if (n > nPages) {
- break;
- }
- ⑸ OsVmPhysPagesFree(page, order);
- nPages -= n;
- page += n;
- }
- while (nPages > 0) {
- ⑹ order = LOS_HighBitGet(nPages);
- n = VM_ORDER_TO_PAGES(order);
- ⑺ OsVmPhysPagesFree(page, order);
- nPages -= n;
- page += n;
- }
- }
3.2.2.3 函數(shù)OsVmPhysPagesFree
函數(shù)OsVmPhysPagesFree()釋放內(nèi)存頁到對應(yīng)的空閑內(nèi)存頁鏈表。內(nèi)存頁塊釋放時,會在當前鏈表找地址連續(xù)的伙伴內(nèi)存頁塊進行合并,然后去上一級鏈表上繼續(xù)查找是否存在連續(xù)的伙伴內(nèi)存頁塊。⑴做傳入?yún)?shù)校驗。⑵處需要至少是倒數(shù)第二個鏈表,這樣內(nèi)存頁節(jié)點可以和大索引鏈表上的節(jié)點合并。⑶處獲取內(nèi)存頁對應(yīng)的物理內(nèi)存地址,然后后面會開始do-while循環(huán),查找是否存在連續(xù)的內(nèi)存頁節(jié)點。⑷處的VM_ORDER_TO_PHYS(order)計算出鏈表索引值對應(yīng)的伙伴位圖,然后進行異或運算計算出伙伴內(nèi)存頁的物理內(nèi)存地址。⑸處物理地址轉(zhuǎn)換為內(nèi)存頁結(jié)構(gòu)體,進一步判斷:如果內(nèi)存頁不存在或者不在空閑鏈表上,則跳出循環(huán)while循環(huán)。否則如果伙伴內(nèi)存節(jié)點存在,則執(zhí)行⑹把伙伴頁從鏈表上移除,然后索引值加1。⑺處鏈表索引加1,然后進行邏輯與計算得到物理內(nèi)存地址。此時物理內(nèi)存地址,和合并的兩塊內(nèi)存頁塊地址連續(xù)。該內(nèi)存地址在高一級的空閑鏈表上不一定存在,存在則繼續(xù)合并,不存在則退出循環(huán)。當索引order為8,要插入到最后一個鏈表上時,或者沒有再找到可以合并的節(jié)點時,則直接執(zhí)行⑻插入內(nèi)存頁節(jié)點到空閑鏈表上。
- VOID OsVmPhysPagesFree(LosVmPage *page, UINT8 order)
- {
- paddr_t pa;
- LosVmPage *buddyPage = NULL;
- ⑴ if ((page == NULL) || (order >= VM_LIST_ORDER_MAX)) {
- return;
- }
- ⑵ if (order < VM_LIST_ORDER_MAX - 1) {
- ⑶ pa = VM_PAGE_TO_PHYS(page);
- do {
- ⑷ pa ^= VM_ORDER_TO_PHYS(order);
- ⑸ buddyPage = OsVmPhysToPage(pa, page->segID);
- if ((buddyPage == NULL) || (buddyPage->order != order)) {
- break;
- }
- ⑹ OsVmPhysFreeListDel(buddyPage);
- order++;
- ⑺ pa &= ~(VM_ORDER_TO_PHYS(order) - 1);
- page = OsVmPhysToPage(pa, page->segID);
- } while (order < VM_LIST_ORDER_MAX - 1);
- }
- ⑻ OsVmPhysFreeListAdd(page, order);
- }
3.3 查詢物理頁地址接口
3.3.1 函數(shù)LOS_VmPageGet()
函數(shù)LOS_VmPageGet用于根據(jù)物理內(nèi)存地址參數(shù)計算對應(yīng)的物理內(nèi)存頁結(jié)構(gòu)體地址。⑴處遍歷物理內(nèi)存段,調(diào)用函數(shù)OsVmPhysToPage根據(jù)物理內(nèi)存地址和內(nèi)存段編號計算物理內(nèi)存頁結(jié)構(gòu)體,該函數(shù)后文再分析。⑵處如果獲取的物理內(nèi)存頁結(jié)構(gòu)體不為空,則跳出循環(huán),返回物理內(nèi)存頁結(jié)構(gòu)體指針。
- LosVmPage *LOS_VmPageGet(PADDR_T paddr)
- {
- INT32 segID;
- LosVmPage *page = NULL;
- for (segID = 0; segID < g_vmPhysSegNum; segID++) {
- ⑴ page = OsVmPhysToPage(paddr, segID);
- ⑵ if (page != NULL) {
- break;
- }
- }
- return page;
- }
繼續(xù)看下函數(shù)OsVmPhysToPage的代碼。⑴處如果參數(shù)傳入的物理內(nèi)存地址不在指定的物理內(nèi)存段的地址范圍之內(nèi)則返回NULL。⑵處計算物理內(nèi)存地址相對內(nèi)存段開始地址的偏移值。⑶處根據(jù)偏移值計算出偏移的內(nèi)存頁的數(shù)目,然后返回物理內(nèi)存地址對應(yīng)的物理頁結(jié)構(gòu)體的地址。
- LosVmPage *OsVmPhysToPage(paddr_t pa, UINT8 segID)
- {
- struct VmPhysSeg *seg = NULL;
- paddr_t offset;
- if (segID >= VM_PHYS_SEG_MAX) {
- LOS_Panic("The page segment id(%d) is invalid\n", segID);
- }
- seg = &g_vmPhysSeg[segID];
- ⑴ if ((pa < seg->start) || (pa >= (seg->start + seg->size))) {
- return NULL;
- }
- ⑵ offset = pa - seg->start;
- ⑶ return (seg->pageBase + (offset >> PAGE_SHIFT));
- }
3.3.2 函數(shù)LOS_PaddrToKVaddr
函數(shù)LOS_PaddrToKVaddr根據(jù)物理地址獲取其對應(yīng)的內(nèi)核虛擬地址。⑴處遍歷物理內(nèi)存段數(shù)組,然后在⑵處判斷如果物理地址處于遍歷到的物理內(nèi)存段的地址范圍內(nèi),則執(zhí)行⑶,傳入的物理內(nèi)存地址相對物理內(nèi)存開始地址的偏移加上內(nèi)核態(tài)虛擬地址空間的開始地址就是物理地址對應(yīng)的內(nèi)核虛擬地址。
- VADDR_T *LOS_PaddrToKVaddr(PADDR_T paddr)
- {
- struct VmPhysSeg *seg = NULL;
- UINT32 segID;
- for (segID = 0; segID < g_vmPhysSegNum; segID++) {
- ⑴ seg = &g_vmPhysSeg[segID];
- ⑵ if ((paddr >= seg->start) && (paddr < (seg->start + seg->size))) {
- ⑶ return (VADDR_T *)(UINTPTR)(paddr - SYS_MEM_BASE + KERNEL_ASPACE_BASE);
- }
- }
- return (VADDR_T *)(UINTPTR)(paddr - SYS_MEM_BASE + KERNEL_ASPACE_BASE);
- }
3.4 其他函數(shù)
3.4.1 函數(shù)OsPhysSharePageCopy
函數(shù)OsPhysSharePageCopy用于復(fù)制共享內(nèi)存頁。 ⑴處進行參數(shù)校驗, ⑵處獲取老內(nèi)存頁, ⑶處獲取內(nèi)存段。⑷處如果老內(nèi)存頁引用計數(shù)為1,則把老物理內(nèi)存地址直接賦值給新物理內(nèi)存地址。⑸處如果內(nèi)存頁有多個引用,則先轉(zhuǎn)化為虛擬內(nèi)存地址,然后執(zhí)行⑹進行內(nèi)存頁的內(nèi)容復(fù)制。⑺刷新新老內(nèi)存頁的引用計數(shù)。
- VOID OsPhysSharePageCopy(PADDR_T oldPaddr, PADDR_T *newPaddr, LosVmPage *newPage)
- {
- UINT32 intSave;
- LosVmPage *oldPage = NULL;
- VOID *newMem = NULL;
- VOID *oldMem = NULL;
- LosVmPhysSeg *seg = NULL;
- ⑴ if ((newPage == NULL) || (newPaddr == NULL)) {
- VM_ERR("new Page invalid");
- return;
- }
- ⑵ oldPage = LOS_VmPageGet(oldPaddr);
- if (oldPage == NULL) {
- VM_ERR("invalid oldPaddr %p", oldPaddr);
- return;
- }
- ⑶ seg = &g_vmPhysSeg[oldPage->segID];
- LOS_SpinLockSave(&seg->freeListLock, &intSave);
- ⑷ if (LOS_AtomicRead(&oldPage->refCounts) == 1) {
- *newPaddr = oldPaddr;
- } else {
- ⑸ newMem = LOS_PaddrToKVaddr(*newPaddr);
- oldMem = LOS_PaddrToKVaddr(oldPaddr);
- if ((newMem == NULL) || (oldMem == NULL)) {
- LOS_SpinUnlockRestore(&seg->freeListLock, intSave);
- return;
- }
- ⑹ if (memcpy_s(newMem, PAGE_SIZE, oldMem, PAGE_SIZE) != EOK) {
- VM_ERR("memcpy_s failed");
- }
- ⑺ LOS_AtomicInc(&newPage->refCounts);
- LOS_AtomicDec(&oldPage->refCounts);
- }
- LOS_SpinUnlockRestore(&seg->freeListLock, intSave);
- return;
- }
總結(jié)
本文首先了解了物理內(nèi)存管理的結(jié)構(gòu)體,接著閱讀了物理內(nèi)存如何初始化,然后分析了物理內(nèi)存的申請、釋放和查詢等操作接口的源代碼。
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)