日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

c++ mmap写入速度_内存管理(24)mmap和缺页中断

發布時間:2024/7/19 c/c++ 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c++ mmap写入速度_内存管理(24)mmap和缺页中断 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

相關文件:

mm/mlock.c

mm/util.c

mm/mmap.c

include/linux/slab.h

mmap系統調用陷入內核中會調用vm_mmap_pgoff=>do_mmap_pgoff函數來真正完成mmap操作

1.1.do_mmap_pgoff函數(關鍵部分代碼)

do_mmap_pgoff

  • 16行:對需要映射的內存長度頁對齊
  • 20行:get_unmapped_area返回需要映射的地址空間
  • 25行:建立映射關系,如果定義了VM_LOCKED還要立即申請物理內存,該函數的實現細節請看1.2小節

1.2.mmap_region函數(關鍵部分代碼)

mmap_region

  • 40行:查找符合條件的vma
  • 46行:合并相鄰的vma
  • 49行:如果沒找到合適的vma則調用kmem_cache_zalloc申請一個vma結構,這個函數前面也說過
  • 51行:把初始化好的vma插入mm下的內存管理樹結構
  • 55行:配置vma的訪問權限

2.缺頁中斷(armv7架構)

相關文件:

mm/memory.c

arch/arm/mm/fault.c

缺頁中斷與具體的處理器架構密切相關。以ARM為例,頁面轉換失效和頁面訪問權限失效對應的核心處理函數為do_page_fault。

缺頁中斷基本流程

2.1.do_page_fault函數(關鍵部分)

do_page_fault函數-1

  • 69行:處于中斷上下文或者禁止搶占時跳轉到no_context標簽
  • 71行:用戶空間添加FAULT_FLAG_USER標志
  • 73行:具備FSR_WRITE權限則添加FAULT_FLAG_WRITE標志
  • 76行:真正處理缺頁中斷的函數,詳情看小節2.2

do_page_fault函數-2

  • 85行:不屬于以上異常就說明缺頁中斷正常處理完成
  • 88行:缺頁中斷處理有異常發生,如果是內核空間跳轉到no_context標簽執行__do_kernel_fault函數
  • 90行:VM_FAULT_OOM則調用pagefault_out_of_memory發送OOM信號
  • 95行:用戶空間則向進程發送SIGSEGV信號,進程中斷
  • 99行:__do_kernel_fault函數發送Oops錯誤

2.2.__do_page_fault函數(關鍵部分)

__do_page_fault函數

  • 112行:查找vma
  • 115行:vma訪問權限
  • 120行:缺頁中斷處理,詳見2.3

2.3.__handle_mm_fault函數(關鍵部分)

__handle_mm_fault函數

  • 141~148行:獲取到addr所對應的PGD、PUD、PMD、PTE
  • 150行:handle_pte_fault處理缺頁中斷,詳見2.4

2.4.handle_pte_fault函數(關鍵部分)

handle_pte_fault函數-1

176行:如果頁面不在內存中(還未映射真正的頁),調用pte_none177行:頁面為空。對于文件映射通常會調用do_fault(詳見2.6);否則表示匿名映射則會調用do_anonymous_page(詳見2.5)186行:頁面不為空,表示正處于交換內存中,調用do_swap_page函數,詳見2.7189行:寫異常190行:如果pte為只讀權限,調用do_swap_page函數193行:如果具備寫屬性,L_PTE_DIRTY置位

handle_pte_fault函數-2

  • 189行:設置L_PTE_YONG位
  • 190行:如果pte頁面項有變化就要寫入物理頁面項,并更新TLB cache

2.5.do_anonymous_page函數

do_anonymous_page函數-1

  • 225行:判斷當前VMA是否需要增加一個guard page作為安全墊
  • 229~236行:對于只讀的VMA,系統使用0號頁面生成新的PTE entry,0號頁面是在paging_init中初始化的,前面提過。使用pte_offset_map_lock能得到頁表項。如果表項不為空則跳轉到setpte處更新到硬件表中。

do_anonymous_page函數-2

241行:分配一個可寫的匿名頁面,最終調用伙伴系統的alloc_pages,優先選擇高端內存254~256行:通過mk_xxx生成一個新的pte entry262行:inc_mm_counter_fast增加系統中匿名頁面的引用計數263行增加到RMAP反向映射系統中265行:把匿名頁添加到LRU鏈表中,kswap中會用到267行:設置pte entry到硬件頁表中

do_anonymous_page函數-3

  • 270行:刷新TLB和cache

2.6.do_fault函數

do_fault函數

  • 300行:只讀缺頁異常,詳見2.8小節
  • 303行:私有映射且發生寫時拷貝缺頁異常,詳見2.9小節
  • 305行:公有映射寫缺頁異常,詳見2.10小節

2.7.do_swap_page函數

與2.8和2.9類似

2.8.do_read_fault函數

static int do_read_fault(struct mm_struct *mm, struct vm_area_struct *vma,unsigned long address, pmd_t *pmd,pgoff_t pgoff, unsigned int flags, pte_t orig_pte){struct page *fault_page;if (vma->vm_ops->map_pages && fault_around_bytes >> PAGE_SHIFT > 1) {//拿到缺頁異常地址addr所對應的ptepte = pte_offset_map_lock(mm, pmd, address, &ptl);/*以缺頁異常地址為中心,從start_addr開始檢查相應的pte是否為空,若為*空則從這個pte開始到max_pgoff為止使用map_pages()來映射PTE。這么做為*了提前建立缺頁地址(進程地址空間)與(現存)page cache的映射關系,*減少缺頁中斷的次數從而提高效率。*/do_fault_around(vma, address, pte, pgoff, flags);//頁面內容在剛剛被系統修改了,跳轉到unlock_out標簽if (!pte_same(*pte, orig_pte))goto unlock_out;pte_unmap_unlock(pte, ptl);}//為缺頁異常地址分配page cache ret = __do_fault(vma, address, pgoff, flags, NULL, &fault_page);if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE | VM_FAULT_RETRY)))return ret;//拿到映射好的缺頁地址的PTEpte = pte_offset_map_lock(mm, pmd, address, &ptl);if (unlikely(!pte_same(*pte, orig_pte))) {pte_unmap_unlock(pte, ptl);unlock_page(fault_page);page_cache_release(fault_page);return ret;}//為PTE創建條目,并加入反向映射機制do_set_pte(vma, address, fault_page, pte, false, false);unlock_page(fault_page);unlock_out://放棄映射pte_unmap_unlock(pte, ptl);return ret;}

2.9.do_cow_fault函數

//省略部分錯誤判斷static int do_cow_fault(struct mm_struct *mm, struct vm_area_struct *vma,unsigned long address, pmd_t *pmd,pgoff_t pgoff, unsigned int flags, pte_t orig_pte){pte_t *pte;int ret;if (unlikely(anon_vma_prepare(vma)))return VM_FAULT_OOM;//以GFP_HIGHUSER_MOVABLE分配掩碼分配一個物理頁面new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, address);if (mem_cgroup_try_charge(new_page, mm, GFP_KERNEL, &memcg)) {page_cache_release(new_page);return VM_FAULT_OOM;}//讀取文件內容到fault_pageret = __do_fault(vma, address, pgoff, flags, new_page, &fault_page);if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE | VM_FAULT_RETRY)))goto uncharge_out;if (fault_page)//拷貝內容到物理頁面copy_user_highpage(new_page, fault_page, address, vma);__SetPageUptodate(new_page);//取得對應的PTEpte = pte_offset_map_lock(mm, pmd, address, &ptl);//為對應PTE創建條目再添加到反向映射機制do_set_pte(vma, address, new_page, pte, true, true);mem_cgroup_commit_charge(new_page, memcg, false);//物理頁面加入LRU隊列進行管理,內存回收會用到lru_cache_add_active_or_unevictable(new_page, vma);pte_unmap_unlock(pte, ptl);if (fault_page) {unlock_page(fault_page);page_cache_release(fault_page);} else {i_mmap_unlock_read(vma->vm_file->f_mapping);}return ret;uncharge_out:mem_cgroup_cancel_charge(new_page, memcg);page_cache_release(new_page);return ret;}

2.10.do_shared_fault函數

與2.8和2.9類似

2.11.do_fault_around函數

static void do_fault_around(struct vm_area_struct *vma, unsigned long address,pte_t *pte, pgoff_t pgoff, unsigned int flags){unsigned long start_addr, nr_pages, mask;pgoff_t max_pgoff;struct vm_fault vmf;int off;/*fault_around_bytes是一個全局變量,等于16個page的大小,所以此處nr_pages=16*/nr_pages = ACCESS_ONCE(fault_around_bytes) >> PAGE_SHIFT;//以16頁對齊為步長計算掩碼mask = ~(nr_pages * PAGE_SIZE - 1) & PAGE_MASK;//以16頁對齊,取缺頁地址和vm_start較大的那個為掃描PTE的起始地址start_addr = max(address & mask, vma->vm_start);/*PTRS_PER_PTE 表示每個PTE項所對應的條目數,此處為512也就是1個PTE對應512頁*這一步相當于取缺頁地址和start_addr的偏離(頁數單位)的絕對值*/off = ((address - start_addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);//查找PTE的起始位置pte -= off;pgoff -= off;/* * max_pgoff is either end of page table or end of vma * or fault_around_pages() from pgoff, depending what is nearest. */max_pgoff = pgoff - ((start_addr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) +PTRS_PER_PTE - 1;max_pgoff = min3(max_pgoff, vma_pages(vma) + vma->vm_pgoff - 1,pgoff + nr_pages - 1);/* Check if it makes any sense to call ->map_pages */while (!pte_none(*pte)) {if (++pgoff > max_pgoff)return;start_addr += PAGE_SIZE;if (start_addr >= vma->vm_end)return;pte++;}//找到為空的PTE,則從此處開始到max_pgoff映射PTEvmf.virtual_address = (void __user *) start_addr;vmf.pte = pte;vmf.pgoff = pgoff;vmf.max_pgoff = max_pgoff;vmf.flags = flags;vma->vm_ops->map_pages(vma, &vmf);} 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的c++ mmap写入速度_内存管理(24)mmap和缺页中断的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。