更新日期: 2022/06/01 来源: https://gitee.com/weharmony/kernel_liteos_a_note
los_vm_scan.c 文件参考

浏览源代码.

函数

VOID OsUnmapPageLocked (LosFilePage *page, LosMapInfo *info)
 
VOID OsUnmapAllLocked (LosFilePage *page)
 解除文件页在所有进程的映射 更多...
 
VOID OsLruCacheAdd (LosFilePage *fpage, enum OsLruList lruType)
 
VOID OsLruCacheDel (LosFilePage *fpage)
 
BOOL OsInactiveListIsLow (LosVmPhysSeg *physSeg)
 非活动文件页低于活动文件页吗 更多...
 
STATIC INLINE VOID OsMoveToActiveList (LosFilePage *fpage)
 
STATIC INLINE VOID OsMoveToInactiveList (LosFilePage *fpage)
 
STATIC INLINE VOID OsMoveToActiveHead (LosFilePage *fpage)
 
STATIC INLINE VOID OsMoveToInactiveHead (LosFilePage *fpage)
 
VOID OsPageRefIncLocked (LosFilePage *fpage)
 
VOID OsPageRefDecNoLock (LosFilePage *fpage)
 
VOID OsShrinkActiveList (LosVmPhysSeg *physSeg, int nScan)
 缩小活动页链表 更多...
 
int OsShrinkInactiveList (LosVmPhysSeg *physSeg, int nScan, LOS_DL_LIST *list)
 缩小未活动页链表 更多...
 
int OsTryShrinkMemory (size_t nPage)
 

函数说明

◆ OsInactiveListIsLow()

BOOL OsInactiveListIsLow ( LosVmPhysSeg physSeg)

非活动文件页低于活动文件页吗

在文件 los_vm_scan.c94 行定义.

95{
96 return (physSeg->lruSize[VM_LRU_ACTIVE_FILE] >
97 physSeg->lruSize[VM_LRU_INACTIVE_FILE]) ? TRUE : FALSE;//直接对比size,效率杠杠的
98}
@ VM_LRU_ACTIVE_FILE
活动文件页(磁盘)
Definition: los_vm_phys.h:78
@ VM_LRU_INACTIVE_FILE
非活动文件页(磁盘)
Definition: los_vm_phys.h:77
size_t lruSize[VM_NR_LRU_LISTS]
5个双循环链表大小,如此方便得到size
Definition: los_vm_phys.h:92
这是这个函数的调用关系图:

◆ OsLruCacheAdd()

VOID OsLruCacheAdd ( LosFilePage fpage,
enum OsLruList  lruType 
)

在文件 los_vm_scan.c69 行定义.

70{
71 UINT32 intSave;
72 LosVmPhysSeg *physSeg = fpage->physSeg; //得到页面对应段
73 LosVmPage *page = fpage->vmPage; //得到物理页面
74
75 LOS_SpinLockSave(&physSeg->lruLock, &intSave);//自旋锁:最多只能被一个内核持有,CPU内核 互斥锁
76 OsSetPageActive(page); //设置页面为活动页
77 OsCleanPageReferenced(page);//清除页面被引用位
78 physSeg->lruSize[lruType]++; //lruType页总size++
79 LOS_ListTailInsert(&physSeg->lruList[lruType], &fpage->lru);//加入lruType页双循环链表中
80
81 LOS_SpinUnlockRestore(&physSeg->lruLock, intSave);//解锁
82}
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListTailInsert(LOS_DL_LIST *list, LOS_DL_LIST *node)
Insert a node to the tail of a doubly linked list.
Definition: los_list.h:244
VOID LOS_SpinUnlockRestore(SPIN_LOCK_S *lock, UINT32 intSave)
Definition: los_spinlock.c:108
VOID LOS_SpinLockSave(SPIN_LOCK_S *lock, UINT32 *intSave)
Definition: los_spinlock.c:98
unsigned int UINT32
Definition: los_typedef.h:57
STATIC INLINE VOID OsSetPageActive(LosVmPage *page)
给页面贴上活动的标签
STATIC INLINE VOID OsCleanPageReferenced(LosVmPage *page)
给页面撕掉被引用的标签
LOS_DL_LIST lru
lru节点, 结合 LosVmPhysSeg: LOS_DL_LIST lruList[VM_NR_LRU_LISTS] 理解
struct VmPage * vmPage
物理页框
struct VmPhysSeg * physSeg
物理页框描述符 虚拟内存体现的是程序对内存资源的需求,而物理内存是对该请求的供应。 伙伴算法的思想是:把内存中连续的空闲页框空间看成是空闲页框块,并按照它们的大小(连续页框的数目)分组
Definition: los_vm_page.h:53
物理段描述符
Definition: los_vm_phys.h:85
LOS_DL_LIST lruList[VM_NR_LRU_LISTS]
页面置换算法,5个双循环链表头,它们分别描述五中不同类型的链表
Definition: los_vm_phys.h:93
SPIN_LOCK_S lruLock
用于置换的自旋锁,用于操作lruList
Definition: los_vm_phys.h:91
函数调用图:
这是这个函数的调用关系图:

◆ OsLruCacheDel()

VOID OsLruCacheDel ( LosFilePage fpage)

在文件 los_vm_scan.c85 行定义.

86{
87 LosVmPhysSeg *physSeg = fpage->physSeg; //得到页面对应段
88 int type = OsIsPageActive(fpage->vmPage) ? VM_LRU_ACTIVE_FILE : VM_LRU_INACTIVE_FILE;//得到页面LRU类型
89
90 physSeg->lruSize[type]--; //type页总size--
91 LOS_ListDelete(&fpage->lru);//将自己从lru链表中摘出来
92}
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListDelete(LOS_DL_LIST *node)
Definition: los_list.h:292
STATIC INLINE BOOL OsIsPageActive(LosVmPage *page)
页面是否活动
函数调用图:
这是这个函数的调用关系图:

◆ OsMoveToActiveHead()

STATIC INLINE VOID OsMoveToActiveHead ( LosFilePage fpage)

在文件 los_vm_scan.c123 行定义.

124{
125 LosVmPhysSeg *physSeg = fpage->physSeg; //得到页面对应段
126 LOS_ListDelete(&fpage->lru); //将自己从lru链表中摘出来
127 LOS_ListTailInsert(&physSeg->lruList[VM_LRU_ACTIVE_FILE], &fpage->lru);//加入活动页双循环链表中
128}
函数调用图:
这是这个函数的调用关系图:

◆ OsMoveToActiveList()

STATIC INLINE VOID OsMoveToActiveList ( LosFilePage fpage)

在文件 los_vm_scan.c101 行定义.

102{
103 LosVmPhysSeg *physSeg = fpage->physSeg; //得到页面对应段
104
105 physSeg->lruSize[VM_LRU_ACTIVE_FILE]++; //活动页总size++
106 physSeg->lruSize[VM_LRU_INACTIVE_FILE]--; //不活动页总size--
107 LOS_ListDelete(&fpage->lru); //将自己从lru链表中摘出来
108 LOS_ListTailInsert(&physSeg->lruList[VM_LRU_ACTIVE_FILE], &fpage->lru);//加入活动页双循环链表中
109}
函数调用图:
这是这个函数的调用关系图:

◆ OsMoveToInactiveHead()

STATIC INLINE VOID OsMoveToInactiveHead ( LosFilePage fpage)

在文件 los_vm_scan.c131 行定义.

132{
133 LosVmPhysSeg *physSeg = fpage->physSeg; //得到页面对应段
134 LOS_ListDelete(&fpage->lru); //将自己从lru链表中摘出来
135 LOS_ListTailInsert(&physSeg->lruList[VM_LRU_INACTIVE_FILE], &fpage->lru);//加入不活动页双循环链表中
136}
函数调用图:
这是这个函数的调用关系图:

◆ OsMoveToInactiveList()

STATIC INLINE VOID OsMoveToInactiveList ( LosFilePage fpage)

在文件 los_vm_scan.c112 行定义.

113{
114 LosVmPhysSeg *physSeg = fpage->physSeg; //得到页面对应段
115
116 physSeg->lruSize[VM_LRU_ACTIVE_FILE]--; //活动页总size--
117 physSeg->lruSize[VM_LRU_INACTIVE_FILE]++; //不活动页总size++
118 LOS_ListDelete(&fpage->lru); //将自己从lru链表中摘出来
119 LOS_ListTailInsert(&physSeg->lruList[VM_LRU_INACTIVE_FILE], &fpage->lru);//加入不活动页双循环链表中
120}
函数调用图:
这是这个函数的调用关系图:

◆ OsPageRefDecNoLock()

VOID OsPageRefDecNoLock ( LosFilePage fpage)

在文件 los_vm_scan.c189 行定义.

190{
191 BOOL isOrgActive;
192 LosVmPage *page = NULL;
193
194 if (fpage == NULL) {
195 return;
196 }
197
198 page = fpage->vmPage;
199 isOrgActive = OsIsPageActive(page);
200
201 if (!OsIsPageReferenced(page) && OsIsPageActive(page)) {//[ref:0,act:1]的情况
202 OsCleanPageActive(page);
204 } else if (OsIsPageReferenced(page)) {
206 }
207
208 if (isOrgActive && !OsIsPageActive(page)) {
210 }
211}
size_t BOOL
Definition: los_typedef.h:88
STATIC INLINE BOOL OsIsPageReferenced(LosVmPage *page)
页面是否被引用,只被一个进程引用的页叫私有页,多个进程引用就是共享页,此为共享内存的本质所在
STATIC INLINE VOID OsSetPageReferenced(LosVmPage *page)
给页面贴上被引用的标签
STATIC INLINE VOID OsCleanPageActive(LosVmPage *page)
给页面撕掉活动的标签
STATIC INLINE VOID OsMoveToInactiveList(LosFilePage *fpage)
Definition: los_vm_scan.c:112
函数调用图:
这是这个函数的调用关系图:

◆ OsPageRefIncLocked()

VOID OsPageRefIncLocked ( LosFilePage fpage)

在文件 los_vm_scan.c145 行定义.

146{
147 BOOL isOrgActive;
148 UINT32 intSave;
149 LosVmPage *page = NULL;
150
151 if (fpage == NULL) {
152 return;
153 }
154
155 LOS_SpinLockSave(&fpage->physSeg->lruLock, &intSave);//要处理lruList,先拿锁
156
157 page = fpage->vmPage;//拿到物理页框
158 isOrgActive = OsIsPageActive(page);//页面是否在活动
159
160 if (OsIsPageReferenced(page) && !OsIsPageActive(page)) {//身兼 不活动和引用标签
161 OsCleanPageReferenced(page);//撕掉引用标签 ref:1, act:0 --> ref:0, act:1
162 OsSetPageActive(page); //贴上活动标签
163 } else if (!OsIsPageReferenced(page)) {
164 OsSetPageReferenced(page);//ref:0, act:0 --> ref:1, act:0
165 }
166
167 if (!isOrgActive && OsIsPageActive(page)) {
168 /* move inactive to active */
169 OsMoveToActiveList(fpage);
170 /* no change, move head */
171 } else {
172 if (OsIsPageActive(page)) {
173 OsMoveToActiveHead(fpage);
174 } else {
176 }
177 }
178
179 LOS_SpinUnlockRestore(&fpage->physSeg->lruLock, intSave);
180}
STATIC INLINE VOID OsMoveToActiveList(LosFilePage *fpage)
Definition: los_vm_scan.c:101
STATIC INLINE VOID OsMoveToActiveHead(LosFilePage *fpage)
Definition: los_vm_scan.c:123
STATIC INLINE VOID OsMoveToInactiveHead(LosFilePage *fpage)
Definition: los_vm_scan.c:131
函数调用图:
这是这个函数的调用关系图:

◆ OsShrinkActiveList()

VOID OsShrinkActiveList ( LosVmPhysSeg physSeg,
int  nScan 
)

缩小活动页链表

在文件 los_vm_scan.c213 行定义.

214{
215 LosFilePage *fpage = NULL;
216 LosFilePage *fnext = NULL;
217 LOS_DL_LIST *activeFile = &physSeg->lruList[VM_LRU_ACTIVE_FILE];
218
219 LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(fpage, fnext, activeFile, LosFilePage, lru) {//一页一页处理
220 if (LOS_SpinTrylock(&fpage->mapping->list_lock) != LOS_OK) {//尝试获取文件页所在的page_mapping锁
221 continue;//接着处理下一文件页
222 }
223
224 /* happend when caller hold cache lock and try reclaim this page *///调用方持有缓存锁并尝试回收此页时发生
225 if (OsIsPageLocked(fpage->vmPage)) {//页面是否被锁
226 LOS_SpinUnlock(&fpage->mapping->list_lock);//失败时,一定要释放page_mapping锁.
227 continue;//接着处理下一文件页
228 }
229
230 if (OsIsPageMapped(fpage) && (fpage->flags & VM_MAP_REGION_FLAG_PERM_EXECUTE)) {//文件页是否被映射而且是个可执行文件 ?
231 LOS_SpinUnlock(&fpage->mapping->list_lock);//是时,一定要释放page_mapping锁.
232 continue;//接着处理下一文件页
233 }
234 //找了可以收缩的文件页
235 OsPageRefDecNoLock(fpage); //将页面移到未活动文件链表
236
237 LOS_SpinUnlock(&fpage->mapping->list_lock); //释放page_mapping锁.
238
239 if (--nScan <= 0) {
240 break;
241 }
242 }
243}
INT32 LOS_SpinTrylock(SPIN_LOCK_S *lock)
Definition: los_spinlock.c:61
VOID LOS_SpinUnlock(SPIN_LOCK_S *lock)
Definition: los_spinlock.c:84
STATIC INLINE BOOL OsIsPageMapped(LosFilePage *page)
文件页是否映射过了
STATIC INLINE BOOL OsIsPageLocked(LosVmPage *page)
页面是否被锁
VOID OsPageRefDecNoLock(LosFilePage *fpage)
Definition: los_vm_scan.c:189
文件页结构体
struct page_mapping * mapping
此结构由文件系统提供,用于描述装入点 见于 ..\third_party\NuttX\fs\fs.h
UINT32 flags
标签
SPIN_LOCK_S list_lock
函数调用图:
这是这个函数的调用关系图:

◆ OsShrinkInactiveList()

int OsShrinkInactiveList ( LosVmPhysSeg physSeg,
int  nScan,
LOS_DL_LIST list 
)

缩小未活动页链表

在文件 los_vm_scan.c245 行定义.

246{
247 UINT32 nrReclaimed = 0;
248 LosVmPage *page = NULL;
249 SPIN_LOCK_S *flock = NULL;
250 LosFilePage *fpage = NULL;
251 LosFilePage *fnext = NULL;
252 LosFilePage *ftemp = NULL;
253 LOS_DL_LIST *inactive_file = &physSeg->lruList[VM_LRU_INACTIVE_FILE];
254
255 LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(fpage, fnext, inactive_file, LosFilePage, lru) {//遍历链表一页一页处理
256 flock = &fpage->mapping->list_lock;
257
258 if (LOS_SpinTrylock(flock) != LOS_OK) {//尝试获取文件页所在的page_mapping锁
259 continue;//接着处理下一文件页
260 }
261
262 page = fpage->vmPage;//获取物理页框
263 if (OsIsPageLocked(page)) {//页面是否被锁
264 LOS_SpinUnlock(flock);
265 continue;//接着处理下一文件页
266 }
267
268 if (OsIsPageMapped(fpage) && (OsIsPageDirty(page) || (fpage->flags & VM_MAP_REGION_FLAG_PERM_EXECUTE))) {
269 LOS_SpinUnlock(flock);//文件页是否被映射而且是个脏页获取是个可执行文件 ?
270 continue;//接着处理下一文件页
271 }
272
273 if (OsIsPageDirty(page)) {//是脏页
274 ftemp = OsDumpDirtyPage(fpage);//备份脏页
275 if (ftemp != NULL) {//备份成功了
276 LOS_ListTailInsert(list, &ftemp->node);//将脏页挂到参数链表上带走
277 }
278 }
279
280 OsDeletePageCacheLru(fpage);//将文件页从LRU和pagecache上摘除
281 LOS_SpinUnlock(flock);
282 nrReclaimed++;//成功回收了一页
283
284 if (--nScan <= 0) {//继续回收
285 break;
286 }
287 }
288
289 return nrReclaimed;
290}
VOID OsDeletePageCacheLru(LosFilePage *page)
删除页高速缓存和LRU,对应 OsAddToPageacheLru
STATIC INLINE BOOL OsIsPageDirty(LosVmPage *page)
页面是否为脏页,所谓脏页就是页内数据是否被更新过,只有脏页才会有写时拷贝
LosFilePage * OsDumpDirtyPage(LosFilePage *oldPage)
备份脏页,老脏页撕掉脏页标签
LOS_DL_LIST node
节点,节点挂到page_mapping.page_list上,链表以 pgoff 从小到大方式排序.
函数调用图:
这是这个函数的调用关系图:

◆ OsTryShrinkMemory()

int OsTryShrinkMemory ( size_t  nPage)

在文件 los_vm_scan.c293 行定义.

294{
295 UINT32 intSave;
296 size_t totalPages;
297 size_t nReclaimed = 0;
298 LosVmPhysSeg *physSeg = NULL;
299 UINT32 index;
300 LOS_DL_LIST_HEAD(dirtyList);//初始化脏页链表,上面将挂所有脏页用于同步到磁盘后回收
301 LosFilePage *fpage = NULL;
302 LosFilePage *fnext = NULL;
303
304 if (nPage <= 0) {
305 nPage = VM_FILEMAP_MIN_SCAN;//
306 }
307
308 if (nPage > VM_FILEMAP_MAX_SCAN) {
309 nPage = VM_FILEMAP_MAX_SCAN;
310 }
311
312 for (index = 0; index < g_vmPhysSegNum; index++) {//遍历整个物理段组
313 physSeg = &g_vmPhysSeg[index];//一段段来
314 LOS_SpinLockSave(&physSeg->lruLock, &intSave);
315 totalPages = physSeg->lruSize[VM_LRU_ACTIVE_FILE] + physSeg->lruSize[VM_LRU_INACTIVE_FILE];//统计所有文件页
316 if (totalPages < VM_FILEMAP_MIN_SCAN) {//文件页占用内存不多的情况下,怎么处理?
317 LOS_SpinUnlockRestore(&physSeg->lruLock, intSave);
318 continue;//放过这一段,找下一段
319 }
320
321 if (OsInactiveListIsLow(physSeg)) {
322 OsShrinkActiveList(physSeg, (nPage < VM_FILEMAP_MIN_SCAN) ? VM_FILEMAP_MIN_SCAN : nPage);//缩小活动页
323 }
324
325 nReclaimed += OsShrinkInactiveList(physSeg, nPage, &dirtyList);//缩小未活动页,带出脏页链表
326 LOS_SpinUnlockRestore(&physSeg->lruLock, intSave);
327
328 if (nReclaimed >= nPage) {//够了,够了,达到目的了.
329 break;//退出收缩
330 }
331 }
332
333 LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(fpage, fnext, &dirtyList, LosFilePage, node) {//遍历处理脏页数据
334 OsDoFlushDirtyPage(fpage);//冲洗脏页数据,将脏页数据回写磁盘
335 }
336
337 return nReclaimed;
338}
VOID OsDoFlushDirtyPage(LosFilePage *fpage)
冲洗脏页数据,将脏页数据回写磁盘
LOS_DL_LIST_HEAD(g_vmSpaceList)
初始化全局虚拟空间节点,所有虚拟空间都挂到此节点上.
INT32 g_vmPhysSegNum
段总数
Definition: los_vm_phys.c:88
struct VmPhysSeg g_vmPhysSeg[VM_PHYS_SEG_MAX]
物理内存采用段页式管理,先切段后伙伴算法页
Definition: los_vm_phys.c:87
BOOL OsInactiveListIsLow(LosVmPhysSeg *physSeg)
非活动文件页低于活动文件页吗
Definition: los_vm_scan.c:94
int OsShrinkInactiveList(LosVmPhysSeg *physSeg, int nScan, LOS_DL_LIST *list)
缩小未活动页链表
Definition: los_vm_scan.c:245
VOID OsShrinkActiveList(LosVmPhysSeg *physSeg, int nScan)
缩小活动页链表
Definition: los_vm_scan.c:213
函数调用图:
这是这个函数的调用关系图:

◆ OsUnmapAllLocked()

VOID OsUnmapAllLocked ( LosFilePage page)

解除文件页在所有进程的映射

在文件 los_vm_scan.c57 行定义.

58{
59 LosMapInfo *info = NULL;
60 LosMapInfo *next = NULL;
61 LOS_DL_LIST *immap = &page->i_mmap;
62
63 LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(info, next, immap, LosMapInfo, node) {//遍历 immap->info 链表
64 OsUnmapPageLocked(page, info);
65 }
66}
VOID OsUnmapPageLocked(LosFilePage *page, LosMapInfo *info)
Definition: los_vm_scan.c:44
LOS_DL_LIST i_mmap
虚拟地址和文件页的映射信息,在一个进程使用文件页之前,需要提前做好文件页在此内存空间的映射关系,如此通过虚拟内存就可以对文件页读写操作.
函数调用图:
这是这个函数的调用关系图:

◆ OsUnmapPageLocked()

VOID OsUnmapPageLocked ( LosFilePage page,
LosMapInfo info 
)

在文件 los_vm_scan.c44 行定义.

45{
46 if (page == NULL || info == NULL) {
47 VM_ERR("UnmapPage error input null!");
48 return;
49 }
50 page->n_maps--;
51 LOS_ListDelete(&info->node);
53 LOS_ArchMmuUnmap(info->archMmu, info->vaddr, 1);
54 LOS_MemFree(m_aucSysMem0, info);//释放虚拟
55}
STATIC INLINE VOID LOS_AtomicDec(Atomic *v)
Atomic auto-decrement. | 对32bit原子数据做减1
Definition: los_atomic.h:323
UINT32 LOS_MemFree(VOID *pool, VOID *ptr)
释放从指定动态内存中申请的内存
Definition: los_memory.c:1369
UINT8 * m_aucSysMem0
异常交互动态内存池地址的起始地址,当不支持异常交互特性时,m_aucSysMem0等于m_aucSysMem1。
Definition: los_memory.c:107
STATUS_T LOS_ArchMmuUnmap(LosArchMmu *archMmu, VADDR_T vaddr, size_t count)
LOS_ArchMmuUnmap 解除进程空间虚拟地址区间与物理地址区间的映射关系
Definition: los_arch_mmu.c:619
UINT32 n_maps
VADDR_T vaddr
虚拟地址.每个进程访问同一个文件页的虚拟地址都是不一样的
LosArchMmu * archMmu
mmu完成vaddr和page->vmPage->physAddr物理地址的映射
LOS_DL_LIST node
节点,挂到page->i_mmap链表上.链表上记录要操作文件页的进程对这个page的映射信息
Atomic refCounts
Definition: los_vm_page.h:57
函数调用图:
这是这个函数的调用关系图: