首先進程地址空間和進程記憶體地區是兩個概念:
1.進程地址空間:系統中每個使用者空間進程所看到的記憶體(虛擬記憶體).核心採用mm_struct結構來描述進程地址空間。
2.進程的記憶體地區:在進程地址空間中,我們更關心的是進程有權訪問的虛擬記憶體地址區間,這些可以被合法訪問的地址區間成為記憶體地區。如果進程訪問不再有效範圍之內的記憶體,核心會終止進程提示段錯誤v。用vm_area_struct結構表示。
vm_area_struct包含在mm_struct之中,在核心中被組織成單鏈表和紅/黑樹狀結構的形式。便於便利和尋找。
mm_struct在核心中通過mmlist域連結成一個雙向鏈表。該鏈表的首元素是init_mm,它代表init進程的地址空間。
mm_struct與核心線程:核心線程沒有進程地址空間,也沒有相關的記憶體描述符,核心線程對應的mm_struct為空白,核心線程沒有進程上下文。為了避免核心線程為記憶體描述符和頁表浪費記憶體,也為了當新核心線程運行時,避免處理器周期性向新地址空間進程切換,核心線程使用前一個進程的記憶體描述符。
當一個進程被調度時,該進程的mm域指向的地址空間被裝載到記憶體,進程描述符中的active_mm域會被更新指向新的地址空間。核心線程的mm_struct域為空白,所以當核心發現該域為空白時,為自動保留上一個進程的地址空間。
操作記憶體地區:find_vma(struct mm_struct *mm, unsigned long addr) 返回首個包含addr地址中的vma
struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)
{
struct vma_area_struct *vma = NULL;
vma = mm->mmap_cache; //用鏈表的形式初始化
if(!(vma&&vma->vm_end>addr&&vma->vm_start<=addr)
struct rb_node *rb_node;
rb_node = mm->mm_rb.rb_node;
vma = NULL;
while(rb_node)
struct vma_area_struct *vma_temp;
vma_temp = rb_entry(rb_node, struct vma_area, vm_rb);
if(vma_temp->vm_end > addr)
vma = vma_temp;
if(vma->vm_start >= addr)
break;
rb_node = rb_node -> rb_left;
else
rb_node = rb_node -> rb_right;
if(vma)
mm->mmap_cache = vma;
return vma;
}
mmap和do_mmap函數:這兩個函數是用於申請VMA並返回起始地址。(並不是申請進程地址空間)
當系統調用do_mmap()中存在無效參數時,它會返回一個負值;否則,它會在虛擬記憶體中分配一個合適的新記憶體地區。如果有可能的話,還會將新地區與就地區進行合并,否則核心從vm_area_cache的slab緩衝中分配一個vm_area_struct結構體,並且使用vm_link()函數將新分配的記憶體地區添加到進程地址空間的記憶體地區鏈表中和紅/黑樹狀結構中,還要更新記憶體描述符中的total_vm域並返回新分配地址區間的首地址。
}