提交 d0b4bae4 编写于 作者: 鸿蒙内核源码分析's avatar 鸿蒙内核源码分析

注解物理内存是如何管理的?伙伴算法/LRU如何分配/置换物理页框?

搜索 @note_pic 可以查看全部字符图
搜索 @note_why 是注者尚未看明白的地方,如果您看明白了,请告诉注者完善
搜索 @note_thinking 是注者的思考和吐槽的地方
搜索 @note_#if0 是由第三方项目提供不由内核源码中定义的极为重要的结构体,为方便理解而添加的。
搜索 @note_good 是注者给源码点赞的地方
上级 f1ae720c
......@@ -29,7 +29,9 @@
搜索 **[@note_thinking]()** 是注者的思考和建议
搜索 **[@note_#if0]()** 是由第三方项目提供不由内核源码中定义的极为重要的结构体,为方便理解而添加的。
搜索 **[@note_#if0]()** 是由第三方项目提供不在内核源码中定义的极为重要结构体,为方便理解而添加的。
搜索 **[@note_good]()** 是注者给源码点赞的地方
- ### **理解内核的三个层级**
......
......@@ -50,16 +50,16 @@ extern "C" {
typedef struct VmPage { //物理页框描述符
LOS_DL_LIST node; /**< vm object dl list */ //虚拟内存节点,通过它挂到全局g_vmPhysSeg[segID]->freeList[order]物理页框链表上
UINT32 index; /**< vm page index to vm object */ //索引位置
PADDR_T physAddr; /**< vm page physical addr */ //物理页框起始物理地址,只能用于计算,不会用于操作(读/写数据==)
PADDR_T physAddr; /**< vm page physical addr */ //物理页框起始物理地址,只能用于计算,不会用于操作(读/写数据==),注意:不可能存在两个物理地址一样的物理页框,
Atomic refCounts; /**< vm page ref count */ //被引用次数,共享内存会被多次引用
UINT32 flags; /**< vm page flags */ //页标签,同时可以有多个标签(共享/引用/活动/被锁==)
UINT8 order; /**< vm page in which order list */ //被安置在伙伴算法的几号序列( 2^0,2^1,2^2,...,2^order)
UINT8 segID; /**< the segment id of vm page */ //所属段ID
UINT16 nPages; /**< the vm page is used for kernel heap */ //页总数,页大小4K的倍数
UINT16 nPages; /**< the vm page is used for kernel heap */ //分配页数,标识从本页开始连续的几页将一块被分配
} LosVmPage;
extern LosVmPage *g_vmPageArray;//物理内存所有页框(page frame)记录数组
extern size_t g_vmPageArraySize;//物理内存总页框(page frame)数
extern LosVmPage *g_vmPageArray;//物理页框(page frame)池
extern size_t g_vmPageArraySize;//物理总页框(page frame)数
LosVmPage *LOS_VmPageGet(PADDR_T paddr);
VOID OsVmPageStartup(VOID);
......
......@@ -57,7 +57,7 @@ LRU是Least Recently Used的缩写,即最近最少使用页面置换算法,
#define VM_PAGE_TO_PHYS(page) (page->physAddr)//获取页面物理地址
#define VM_ORDER_TO_PAGES(order) (1 << (order))//伙伴算法由order 定位到该块组的页面单位,例如:order=2时,page[4]
#define VM_ORDER_TO_PHYS(order) (1 << (PAGE_SHIFT + (order)))//跳块例如 order=2 就是跳4页
#define VM_ORDER_TO_PHYS(order) (1 << (PAGE_SHIFT + (order)))//通过order块组跳到物理地址
#define VM_PHYS_TO_ORDER(phys) (min(LOS_LowBitGet((phys) >> PAGE_SHIFT), VM_LIST_ORDER_MAX - 1))//通过物理地址定位到order
struct VmFreeList {
......@@ -78,11 +78,9 @@ typedef struct VmPhysSeg {//物理段描述符
PADDR_T start; /* The start of physical memory area */ //物理内存的开始地址
size_t size; /* The size of physical memory area */ //物理内存的大小
LosVmPage *pageBase; /* The first page address of this area */ //本段首个物理页框地址
SPIN_LOCK_S freeListLock; /* The buddy list spinlock */ //伙伴算法自旋锁,用于操作freeList上锁
struct VmFreeList freeList[VM_LIST_ORDER_MAX]; /* The free pages in the buddy list */ //伙伴算法的分组,默认分成10组 2^0,2^1,...,2^VM_LIST_ORDER_MAX
SPIN_LOCK_S lruLock;//置换锁
SPIN_LOCK_S lruLock; //用于置换的自旋锁,用于操作lruList
size_t lruSize[VM_NR_LRU_LISTS]; //5个双循环链表大小,如此方便得到size
LOS_DL_LIST lruList[VM_NR_LRU_LISTS]; //页面置换算法,5个双循环链表头,它们分别描述五中不同类型的链表
} LosVmPhysSeg;
......
/*
* Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020, Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "los_vm_boot.h"
#include "los_config.h"
#include "los_base.h"
#include "los_vm_zone.h"
#include "los_vm_map.h"
#include "los_memory_pri.h"
#include "los_vm_page.h"
#include "los_arch_mmu.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
UINTPTR g_vmBootMemBase = (UINTPTR)&__bss_end;//内核空间可用于分配的区域
BOOL g_kHeapInited = FALSE;//内核堆区初始化变量
//虚拟内存区间检查, 需理解 los_vm_zone.h 中画出的鸿蒙虚拟内存全景图
UINT32 OsVmAddrCheck(size_t tempAddr, size_t length)
{
if ((tempAddr >= KERNEL_VMM_BASE) && ((tempAddr + length) <= (PERIPH_UNCACHED_BASE + PERIPH_UNCACHED_SIZE))) {
return LOS_OK;
}
return LOS_NOK;
}
//开机引导分配器分配内存,只有开机时采用的分配方式
VOID *OsVmBootMemAlloc(size_t len)
{
UINTPTR ptr;
if (g_kHeapInited) {// ????? g_kHeapInited 在什么时候会变成 true,没找到代码
VM_ERR("kernel heap has been inited, should not to use boot mem alloc!");
return NULL;
}
ptr = LOS_Align(g_vmBootMemBase, sizeof(UINTPTR));//对齐
g_vmBootMemBase = ptr + LOS_Align(len, sizeof(UINTPTR));//通过改变 g_vmBootMemBase来获取内存
//这样也行,g_vmBootMemBase 真是野蛮粗暴
return (VOID *)ptr;
}
UINT32 OsSysMemInit(VOID)
{
STATUS_T ret;
OsKSpaceInit();//内核空间初始化
ret = OsKHeapInit(OS_KHEAP_BLOCK_SIZE);// 内核动态内存初始化 512K
if (ret != LOS_OK) {
VM_ERR("OsKHeapInit fail");
return LOS_NOK;
}
OsVmPageStartup();// page初始化
OsInitMappingStartUp();// 映射初始化
ret = ShmInit();// 共享内存初始化
if (ret < 0) {
VM_ERR("ShmInit fail");
return LOS_NOK;
}
return LOS_OK;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus */
#endif /* __cplusplus */
/*
* Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020, Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "los_vm_boot.h"
#include "los_config.h"
#include "los_base.h"
#include "los_vm_zone.h"
#include "los_vm_map.h"
#include "los_memory_pri.h"
#include "los_vm_page.h"
#include "los_arch_mmu.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
UINTPTR g_vmBootMemBase = (UINTPTR)&__bss_end;//内核空间可用于分配的区域
BOOL g_kHeapInited = FALSE;//内核堆区初始化变量
//虚拟内存区间检查, 需理解 los_vm_zone.h 中画出的鸿蒙虚拟内存全景图
UINT32 OsVmAddrCheck(size_t tempAddr, size_t length)
{
if ((tempAddr >= KERNEL_VMM_BASE) && ((tempAddr + length) <= (PERIPH_UNCACHED_BASE + PERIPH_UNCACHED_SIZE))) {
return LOS_OK;
}
return LOS_NOK;
}
//开机引导分配器分配内存,只有开机时采用的分配方式
VOID *OsVmBootMemAlloc(size_t len)
{
UINTPTR ptr;
if (g_kHeapInited) {//@note_why 在什么时候会变成true,没找到代码
VM_ERR("kernel heap has been inited, should not to use boot mem alloc!");
return NULL;
}
ptr = LOS_Align(g_vmBootMemBase, sizeof(UINTPTR));//对齐
g_vmBootMemBase = ptr + LOS_Align(len, sizeof(UINTPTR));//通过改变 g_vmBootMemBase来获取内存
//这样也行,g_vmBootMemBase 真是野蛮粗暴
return (VOID *)ptr;
}
UINT32 OsSysMemInit(VOID)
{
STATUS_T ret;
OsKSpaceInit();//内核空间初始化
ret = OsKHeapInit(OS_KHEAP_BLOCK_SIZE);// 内核动态内存初始化 512K
if (ret != LOS_OK) {
VM_ERR("OsKHeapInit fail");
return LOS_NOK;
}
OsVmPageStartup();// 物理内存初始化
OsInitMappingStartUp();// 映射初始化
ret = ShmInit();// 共享内存初始化
if (ret < 0) {
VM_ERR("ShmInit fail");
return LOS_NOK;
}
return LOS_OK;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus */
#endif /* __cplusplus */
......@@ -51,14 +51,17 @@ STATIC VOID OsVmPageInit(LosVmPage *page, paddr_t pa, UINT8 segID)
LOS_AtomicSet(&page->refCounts, 0); //引用次数0
page->physAddr = pa; //物理地址
page->segID = segID; //物理地址使用段管理,段ID
page->order = VM_LIST_ORDER_MAX; //所属伙伴算法块组
page->order = VM_LIST_ORDER_MAX; //所属伙伴算法块组,VM_LIST_ORDER_MAX代表初始化值,不属于任何块组
}
//伙伴算法初始化
STATIC INLINE VOID OsVmPageOrderListInit(LosVmPage *page, size_t nPages)
{
OsVmPhysPagesFreeContiguous(page, nPages);//释放页面使可用于伙伴算法分配
{//@note_why 此时所有页面 page->order 都是 VM_LIST_ORDER_MAX,能顺利的加入伙伴算法的链表吗?
OsVmPhysPagesFreeContiguous(page, nPages);//释放连续的物理页框
}
// page初始化
/******************************************************************************
完成对物理内存整体初始化,本函数一定运行在实模式下
1.申请大块内存g_vmPageArray存放LosVmPage,按4K一页划分物理内存存放在数组中.
******************************************************************************/
VOID OsVmPageStartup(VOID)
{
struct VmPhysSeg *seg = NULL;
......@@ -71,21 +74,21 @@ VOID OsVmPageStartup(VOID)
nPage = OsVmPhysPageNumGet();//得到 g_physArea 总页数
g_vmPageArraySize = nPage * sizeof(LosVmPage);//页表总大小
g_vmPageArray = (LosVmPage *)OsVmBootMemAlloc(g_vmPageArraySize);//申请页表存放区域
g_vmPageArray = (LosVmPage *)OsVmBootMemAlloc(g_vmPageArraySize);//实模式下申请内存,此时还没有初始化MMU
OsVmPhysAreaSizeAdjust(ROUNDUP(g_vmPageArraySize, PAGE_SIZE));// g_physArea 变小
OsVmPhysAreaSizeAdjust(ROUNDUP(g_vmPageArraySize, PAGE_SIZE));//
OsVmPhysSegAdd();// 完成对段的初始化,将段切成一页一页
OsVmPhysInit();// 加入空闲链表和设置置换算法,LRU(最近最久未使用)算法
for (segID = 0; segID < g_vmPhysSegNum; segID++) {
for (segID = 0; segID < g_vmPhysSegNum; segID++) {//遍历物理段
seg = &g_vmPhysSeg[segID];
nPage = seg->size >> PAGE_SHIFT;
for (page = seg->pageBase, pa = seg->start; page <= seg->pageBase + nPage;
nPage = seg->size >> PAGE_SHIFT;//本段总页数
for (page = seg->pageBase, pa = seg->start; page <= seg->pageBase + nPage;//遍历,算出每个页框的物理地址
page++, pa += PAGE_SIZE) {
OsVmPageInit(page, pa, segID);//page初始化
OsVmPageInit(page, pa, segID);//对物理页框进行初始化,注意每页的物理地址都不一样
}
OsVmPageOrderListInit(seg->pageBase, nPage);// 页面分配的排序
OsVmPageOrderListInit(seg->pageBase, nPage);//伙伴算法初始化,将所有页加入空闲链表供分配
}
}
//通过物理地址获取页框
......
......@@ -162,7 +162,7 @@ VOID OsVmPhysInit(VOID)
OsVmPhysLruInit(seg); //初始化LRU置换链表
}
}
//将页框挂入空闲链表,分配物理内存从空闲链表里拿
//将页框挂入空闲链表,分配物理页框从空闲链表里拿
STATIC VOID OsVmPhysFreeListAdd(LosVmPage *page, UINT8 order)
{
struct VmPhysSeg *seg = NULL;
......@@ -240,13 +240,13 @@ STATIC VOID OsVmPhysPagesSpiltUnsafe(LosVmPage *page, UINT8 oldOrder, UINT8 newO
LosVmPage *buddyPage = NULL;
for (order = newOrder; order > oldOrder;) {//把肉剁碎的过程,把多余的肉块切成2^7,2^6...标准块,
order--;//逐一放回仓库,一直切到最后的2^2块
buddyPage = &page[VM_ORDER_TO_PAGES(order)];//@note_why 先把多余的肉割出来,但 没有理解是怎么做到的?
LOS_ASSERT(buddyPage->order == VM_LIST_ORDER_MAX);//@note_why 同样没理解为什么能下这个断言
OsVmPhysFreeListAddUnsafe(buddyPage, order);//将劈开的节点挂到对应序号的链表上
order--;//越切越小,逐一挂到对应的空闲链表上
buddyPage = &page[VM_ORDER_TO_PAGES(order)];//@note_good 先把多余的肉割出来,这句代码很赞!因为LosVmPage本身是在一个大数组上,page[nPages]可直接定位
LOS_ASSERT(buddyPage->order == VM_LIST_ORDER_MAX);//没挂到伙伴算法对应组块空闲链表上的物理页框的order必须是VM_LIST_ORDER_MAX
OsVmPhysFreeListAddUnsafe(buddyPage, order);//将劈开的节点挂到对应序号的链表上,buddyPage->order = order
}
}
//通过物理地址获取所属物理页框
//通过物理地址获取所属参数段的物理页框
LosVmPage *OsVmPhysToPage(paddr_t pa, UINT8 segID)
{
struct VmPhysSeg *seg = NULL;
......@@ -261,7 +261,7 @@ LosVmPage *OsVmPhysToPage(paddr_t pa, UINT8 segID)
}
offset = pa - seg->start;//得到物理地址的偏移量
return (seg->pageBase + (offset >> PAGE_SHIFT));//得到第n页page
return (seg->pageBase + (offset >> PAGE_SHIFT));//得到对应的物理页框
}
/******************************************************************************
......@@ -323,7 +323,7 @@ DONE:
OsVmPhysPagesSpiltUnsafe(page, order, newOrder);//将物理页框劈开,把用不了的页再挂到对应的空闲链表上
return page;
}
//释放物理页,所谓释放物理页就是把页挂到空闲链表中
//释放物理页,所谓释放物理页就是把页挂到空闲链表中
VOID OsVmPhysPagesFree(LosVmPage *page, UINT8 order)
{
paddr_t pa;
......@@ -337,8 +337,8 @@ VOID OsVmPhysPagesFree(LosVmPage *page, UINT8 order)
pa = VM_PAGE_TO_PHYS(page);//获取物理地址
do {
pa ^= VM_ORDER_TO_PHYS(order);//注意这里是高位和低位的 ^= ,也就是说跳到 order块组 物理地址处,此处处理甚妙!
buddyPage = OsVmPhysToPage(pa, page->segID);//如此就能拿到以2^order次方跳的buddyPage
if ((buddyPage == NULL) || (buddyPage->order != order)) {
buddyPage = OsVmPhysToPage(pa, page->segID);//通过物理地址拿到页框
if ((buddyPage == NULL) || (buddyPage->order != order)) {//页框所在组块必须要对应
break;
}
OsVmPhysFreeListDel(buddyPage);//注意buddypage是连续的物理页框 例如order=2时,2^2=4页就是一个块组 |_|_|_|_|
......@@ -350,7 +350,7 @@ VOID OsVmPhysPagesFree(LosVmPage *page, UINT8 order)
OsVmPhysFreeListAdd(page, order);//伙伴算法 空闲节点增加
}
//连续的释放物理页框, 如果8页连在一块是一起释放的,取决于使用了伙伴算法的order
//连续的释放物理页框, 如果8页连在一块是一起释放的
VOID OsVmPhysPagesFreeContiguous(LosVmPage *page, size_t nPages)
{
paddr_t pa;
......@@ -358,11 +358,11 @@ VOID OsVmPhysPagesFreeContiguous(LosVmPage *page, size_t nPages)
size_t count;
size_t n;
while (TRUE) {
while (TRUE) {//死循环
pa = VM_PAGE_TO_PHYS(page);//获取页面物理地址
order = VM_PHYS_TO_ORDER(pa);//通过物理地址找到伙伴算法的级别
n = VM_ORDER_TO_PAGES(order);//通过级别找到物理页块 (1<<order),意思是如果order=3,就是有8个页块
if (n > nPages) {//只剩小于 2的order时,退出循环
n = VM_ORDER_TO_PAGES(order);//通过级别找到物理页块 (1<<order),意思是如果order=3,就可以释放8个页块
if (n > nPages) {//只剩小于2的order时,退出循环
break;
}
OsVmPhysPagesFree(page, order);//释放伙伴算法对应块组
......@@ -377,7 +377,11 @@ VOID OsVmPhysPagesFreeContiguous(LosVmPage *page, size_t nPages)
page += n;
}
}
//获取一定数量的页框
/******************************************************************************
获取一定数量的页框 LosVmPage实体是放在全局大数组中的,
LosVmPage->nPages 标记了分配页数
******************************************************************************/
STATIC LosVmPage *OsVmPhysPagesGet(size_t nPages)
{
UINT32 intSave;
......@@ -392,7 +396,7 @@ STATIC LosVmPage *OsVmPhysPagesGet(size_t nPages)
for (segID = 0; segID < g_vmPhysSegNum; segID++) {
seg = &g_vmPhysSeg[segID];
LOS_SpinLockSave(&seg->freeListLock, &intSave);
page = OsVmPhysPagesAlloc(seg, nPages);//分配指定页数的物理页, 可分析出 nPages 不能大于 256个
page = OsVmPhysPagesAlloc(seg, nPages);//分配指定页数的物理页,nPages需小于伙伴算法一次最大分配页数
if (page != NULL) {
/* */
LOS_AtomicSet(&page->refCounts, 0);//设置引用次数为0
......@@ -441,11 +445,14 @@ VOID LOS_PhysPagesFreeContiguous(VOID *ptr, size_t nPages)
seg = &g_vmPhysSeg[page->segID];
LOS_SpinLockSave(&seg->freeListLock, &intSave);
OsVmPhysPagesFreeContiguous(page, nPages);//Os层具体释放实现
OsVmPhysPagesFreeContiguous(page, nPages);//具体释放实现
LOS_SpinUnlockRestore(&seg->freeListLock, intSave);
}
//通过物理地址获取内核虚拟地址
/******************************************************************************
通过物理地址获取内核虚拟地址
可以看出内核虚拟空间
******************************************************************************/
VADDR_T *LOS_PaddrToKVaddr(PADDR_T paddr)
{
struct VmPhysSeg *seg = NULL;
......@@ -457,8 +464,8 @@ VADDR_T *LOS_PaddrToKVaddr(PADDR_T paddr)
return (VADDR_T *)(UINTPTR)(paddr - SYS_MEM_BASE + KERNEL_ASPACE_BASE);
}
}
return (VADDR_T *)(UINTPTR)(paddr - SYS_MEM_BASE + KERNEL_ASPACE_BASE);
//内核
return (VADDR_T *)(UINTPTR)(paddr - SYS_MEM_BASE + KERNEL_ASPACE_BASE);//
}
VOID LOS_PhysPageFree(LosVmPage *page)
......@@ -556,7 +563,7 @@ struct VmPhysSeg *OsVmPhysSegGet(LosVmPage *page)
return (OsGVmPhysSegGet() + page->segID);
}
//通过总页数 ,获取块组 ,例如需要分配 8个页,返回就是 3 ,例如 1023个 返回就是 10
//通过总页数 ,获取块组 ,例如需要分配 8个页,返回就是3 ,如果是1023 ,返回就是10
UINT32 OsVmPagesToOrder(size_t nPages)
{
UINT32 order;
......
此差异已折叠。
#ifndef _NOTE_IPC_H
#define _NOTE_IPC_H
/****************************************************************
信号量是为了解决task的资源同步问题,有多少资源就设多大的资源最大值
信号量机制:
以一个停车场的运作为例。假设停车场只有三个车位,一开始三个车位都是空的。这时如果同时来了五辆车,
看门人允许其中三辆直接进入,然后放下车拦,剩下的车则必须在入口等待,此后来的车也都不得不在入口处等待。
这时,有一辆车离开停车场,看门人得知后,打开车拦,放入外面的一辆进去,如果又离开两辆,则又可以放入两辆,如此往复。
信号量的规则:
如果当前资源计数器大于0,那么信号量处于触发状态
如果当前资源计数器等于0,那么信号量处于未触发状态
系统绝对不会让当前资源计数器变为负数
当前资源计数器决定不会大于最大资源计数
最大资源计数,表示可以控件的最大资源数量
当前资源计数,表示当前可用资源的数量
****************************************************************/
/* */
/******************************************************************************
******************************************************************************/
#endif
#ifndef _NOTE_IPC_H
#define _NOTE_IPC_H
/****************************************************************
信号量是为了解决task的资源同步问题,有多少资源就设多大的资源最大值
信号量机制:
以一个停车场的运作为例。假设停车场只有三个车位,一开始三个车位都是空的。这时如果同时来了五辆车,
看门人允许其中三辆直接进入,然后放下车拦,剩下的车则必须在入口等待,此后来的车也都不得不在入口处等待。
这时,有一辆车离开停车场,看门人得知后,打开车拦,放入外面的一辆进去,如果又离开两辆,则又可以放入两辆,如此往复。
信号量的规则:
如果当前资源计数器大于0,那么信号量处于触发状态
如果当前资源计数器等于0,那么信号量处于未触发状态
系统绝对不会让当前资源计数器变为负数
当前资源计数器决定不会大于最大资源计数
最大资源计数,表示可以控件的最大资源数量
当前资源计数,表示当前可用资源的数量
****************************************************************/
/* */
/******************************************************************************
******************************************************************************/
#endif
......@@ -4,6 +4,7 @@ git commit -m '注解物理内存是如何管理的?伙伴算法/LRU如何分
搜索 @note_why 是注者尚未看明白的地方,如果您看明白了,请告诉注者完善
搜索 @note_thinking 是注者的思考和吐槽的地方
搜索 @note_#if0 是由第三方项目提供不由内核源码中定义的极为重要的结构体,为方便理解而添加的。
搜索 @note_good 是注者给源码点赞的地方
'
git push origin master
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册