Linux 內核進程管理之基礎
本文轉載自微信公眾號「人人都是極客」,作者布道師Peter。轉載本文請聯系人人都是極客公眾號。
沒有廢話,內存管理暫時告一段落,正式進入進程管理的內容。
內核通過 task_struct 描述進程
用命令 pstree 可以讓內核以樹形的結構把進程之間的關系列出來,如下圖:
這是進程在內核中的結構形式,那么內核是如何來以樹形結構管理描述這些進程的呢?用來描述進程的數據結構,可以理解為進程的屬性。比如進程的狀態、進程的標識(PID)等,都被封裝在了進程描述符 task_struct 這個數據結構中。
- struct task_struct {
- ......
- /* -1 unrunnable, 0 runnable, >0 stopped: */
- //任務狀態。<0是不運行狀態,=0是運行狀態,>0是停止狀態。
- volatile long state;
- ......
- //指向內核棧的指針
- void *stack;
- ......
- /*進程的調度策略,有6種。
- *限期進程調度策略:SCHED_DEADLINE。
- *實時進程調度策略:SCHED_FIFO,SCHED_RR。
- *普通進程調度策略:SCHED_NORMAL,SCHED_BATCH,SCHED_IDLE。
- */
- unsigned int policy;
- ......
- //進程內存管理信息
- struct mm_struct *mm;
- struct mm_struct *active_mm;
- ......
- //進程標識符,用來代表一個進程
- pid_t pid;
- ......
- //線程鏈表
- struct list_head thread_group;
- struct list_head thread_node;
- struct completion *vfork_done;
- ......
- /* Filesystem information: */
- //文件系統信息
- struct fs_struct *fs;
- /* Open file information: */
- //打開文件信息
- struct files_struct *files;
- ......
- /* CPU-specific state of this task: */
- //進程的CPU狀態,切換時,要保存到停止進程的task_struct中
- struct thread_struct thread;
- ......
- };
內核就是通過list_head鏈表把各個進程關系以樹形結構管理起來的。
task_struct 結構體內容太多,這里只列出部分成員變量,感興趣的讀者可以去源碼 include/linux/sched.h頭文件查看。
task_struct 中的主要信息分類:
- 標示符:描述本進程的唯一標識符 pid,用來區別其他進程。
- 狀態:任務狀態,退出代碼,退出信號等
- 優先級:相對于其他進程的優先級
- 程序計數器:程序中即將被執行的下一條指令的地址
- 內存指針:包括程序代碼和進程相關數據的指針,還有和其他進程共享的內存塊的指針
- 上下文數據:進程執行時處理器的寄存器中的數據
- I/O狀態信息:包括顯示的I/O請求,分配的進程I/O設備和進程使用的文件列表
- 記賬信息:可能包括處理器時間總和,使用的時鐘總和,時間限制,記帳號等
- ARM64不用通過struct thread_info thread_info獲取當前task_struct
- static __always_inline struct task_struct *get_current(void)
- {
- unsigned long sp_el0;
- asm ("mrs %0, sp_el0" : "=r" (sp_el0));
- return (struct task_struct *)sp_el0;
- }
- #define current get_current()
可以看出 sp_el0 直接作為 task_struct 返回了。對于ARM64平臺,記錄當前進程的task_struct地址是利用sp0_el1寄存器,當內核執行進程切換時會把當前要運行的進程task_struct地址記錄到該寄存器中。因此我們current查找task_struct時也是很簡單了,不再用通過sp和thread_info去定位了。
- volatile long state
-1是不運行的,=0是運行狀態,>0是停止狀態
Linux中的 ready 和 running 對應的都是TASK_RUNNING標志位,ready 表示進程正處在隊列中,尚未被調度;running 則表示進程正在CPU上運行;
- void *stack
指向內核棧的指針,內核通過 dup_task_struct 為每個進程都分配內核棧空間,并記錄在此。
- struct mm_struct *mm
與進程地址空間相關的信息。
task_struct 的分配和初始化
圖中可知,上層應用通過各種方式創建進程時,最終都會通過 _do_fork 新建一個 task_struct。