本文主要介紹linux內核中進程地址空間的數據結構描述,包括mm_struct/vm_area_struct。進程線性地址區間的分配流程,並對相應的源代碼做了注釋。
內核中的函數以相當直接了當的方式獲得動態內存。當給用戶態進程分配內存時,情況完全不同了。進程對動態內存的請求被認為是不緊迫的,一般來說,內核總是盡量推遲給用戶態進程分配內存。由於用戶進程時不可信任的,因此,內核必須能隨時准備捕獲用戶態進程引起的所有尋址錯誤。當用戶態進程請求動態內存時,並沒有獲得請求的頁框,而僅僅獲得對一個新的線性地址區間的使用權,而這一線性地址區間就成為進程地址空間的一部分。
進程地址空間由允許進程使用的全部線性地址組成。內核可以通過增加或刪除某些線程地址區間來動態地修改進程的地址空間。內核通過所謂線性去得資源來標示線性地址區間,線性區是由起始線性地址、長度和一些訪問權限來描述的。進程獲得新線性區的一些典型情況:
1.但用戶在控制台輸入一條命令時,shell進程創建一個新的進程去執行這個命令。結果是,一個全新的地址空間(也就是一組線性區)分配給新進程。
2.正在運行的進程有可能決定裝入一個完全不同的程序。這時,進程描述符不變,可是在裝入這個程序以前所有的線性區卻被釋放,並有一組新的線性區被分配給這個進程。
3.正在運行的進程可能對一個文件執行內存映像。
4.進程可能持續向他的用戶態堆棧增加數據,知道映像這個堆棧的線性區用完為止,此時,內核也許會決定擴展這個線性區的大小。
5.進程可能創建一個IPC共享線性區來與其他合作進程共享數據。此時,內核給這個進程分配一個新的線性區以實現這個方案。
6.進程可能通過調用類似malloc這樣的函數擴展自己的動態堆。結果是,內核可能決定擴展給這個堆所分配的線性區。
數據結構描述
進程描述符task_struct中的mm字段描述了進程地址空間
- struct mm_struct {
- struct vm_area_struct * mmap; /* list of VMAs */
- struct rb_root mm_rb;
- struct vm_area_struct * mmap_cache; /* last find_vma result */
- unsigned long (*get_unmapped_area) (struct file *filp,
- unsigned long addr, unsigned long len,
- unsigned long pgoff, unsigned long flags);
- void (*unmap_area) (struct mm_struct *mm, unsigned long addr);
- unsigned long mmap_base; /* base of mmap area */
- unsigned long task_size; /* size of task vm space */
- unsigned long cached_hole_size; /* if non-zero, the largest hole below free_area_cache */
- unsigned long free_area_cache; /* first hole of size cached_hole_size or larger */
- pgd_t * pgd;
- atomic_t mm_users; /* How many users with user space? */
- atomic_t mm_count; /* How many references to "struct mm_struct" (users count as 1) */
- int map_count; /* number of VMAs */
- struct rw_semaphore mmap_sem;
- spinlock_t page_table_lock; /* Protects page tables and some counters */
-
- struct list_head mmlist; /* List of maybe swapped mm's. These are globally strung
- * together off init_mm.mmlist, and are protected
- * by mmlist_lock
- */
-
- /* Special counters, in some configurations protected by the
- * page_table_lock, in other configurations by being atomic.
- */
- mm_counter_t _file_rss;
- mm_counter_t _anon_rss;
-
- unsigned long hiwater_rss; /* High-watermark of RSS usage */
- unsigned long hiwater_vm; /* High-water virtual memory usage */
-
- unsigned long total_vm, locked_vm, shared_vm, exec_vm;
- unsigned long stack_vm, reserved_vm, def_flags, nr_ptes;
- unsigned long start_code, end_code, start_data, end_data;
- unsigned long start_brk, brk, start_stack;
- unsigned long arg_start, arg_end, env_start, env_end;
-
- unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */
-
- struct linux_binfmt *binfmt;
-
- cpumask_t cpu_vm_mask;/*用於懶惰TLB交換的位掩碼*/
-
- /* Architecture-specific MM context */
- mm_context_t context;
-
- /* Swap token stuff */
- /*
- * Last value of global fault stamp as seen by this process.
- * In other words, this value gives an indication of how long
- * it has been since this task got the token.
- * Look at mm/thrash.c
- */
- unsigned int faultstamp;
- unsigned int token_priority;
- unsigned int last_interval;
-
- unsigned long flags; /* Must use atomic bitops to access the bits */
-
- struct core_state *core_state; /* coredumping support */
- #ifdef CONFIG_AIO
- spinlock_t ioctx_lock;
- struct hlist_head ioctx_list;/*一步IO上下文鏈表*/
- #endif
- #ifdef CONFIG_MM_OWNER
- /*
- * "owner" points to a task that is regarded as the canonical
- * user/owner of this mm. All of the following must be true in
- * order for it to be changed:
- *
- * current == mm->owner
- * current->mm != mm
- * new_owner->mm == mm
- * new_owner->alloc_lock is held
- */
- struct task_struct *owner;
- #endif
-
- #ifdef CONFIG_PROC_FS
- /* store ref to file /proc/<pid>/exe symlink points to */
- struct file *exe_file;
- unsigned long num_exe_file_vmas;
- #endif
- #ifdef CONFIG_MMU_NOTIFIER
- struct mmu_notifier_mm *mmu_notifier_mm;
- #endif
- };