目的:
初步了解進程描述符 task_struct。
目錄:
Linux的進程
Linux 的進程描述符
task_struct
內核如何找到 task_struct
task_struct 的分配和初始化
實驗:打印 task_struct / thread_info / kernel mode stack
環境:
Linux-4.14 + ARMv7
1. Linux 的進程
進程的術語是 process,是 Linux 最基礎的抽象,另一個基礎抽象是文件。
最簡單的理解,進程就是執行中 (executing, 不等于running) 的程序。
更準確一點的理解,進程包括執行中的程序以及相關的資源(包括cpu狀態、打開的文件、掛起的信號、tty、內存地址空間等)。
一種簡潔的說法:進程 = n*執行流 + 資源,n>=1。
Linux 進程的特點:
通過系統調用 fork() 創建進程,fork() 會復制現有進程來創建一個全新的進程。
內核里,并不嚴格區分進程和線程。
從內核的角度看,調度單位是線程 (即執行流)。可以把線程看做是進程里的一條執行流,1個進程里可以有1個或者多個線程。
內核里,常把進程稱為 task 或者 thread,這樣描述更準確,因為許多進程就只有1條執行流。
內核通過輕量級進程 (lightweight process) 來支持多線程。1個輕量級進程就對應1個線程,輕量級進程之間可以共享打開的文件、地址空間等資源。
2. Linux 的進程描述符
2.1 task_struct
內核里,通過 task_struct 結構體來描述一個進程,稱為進程描述符 (process descriptor),它保存著支撐一個進程正常運行的所有信息。
每一個進程,即便是輕量級進程(即線程),都有1個 task_struct。
sched.h(includelinux) structtask_struct{ structthread_infothread_info; volatilelongstate; void*stack; [...] structmm_struct*mm; [...] pid_tpid; [...] structtask_struct*parent; [...] charcomm[TASK_COMM_LEN]; [...] structfiles_struct*files; [...] structsignal_struct*signal; }
這是一個龐大的結構體,不僅有許多進程相關的基礎字段,還有許多指向其他數據結構的指針。
它包含的字段能完整地描述一個正在執行的程序,包括 cpu 狀態、打開的文件、地址空間、掛起的信號、進程狀態等。
點擊查看大圖
作為初學者,先簡單地了解部分字段就好::
struct thread_info thread_info:進程底層信息,平臺相關,下面會詳細描述。
long state:進程當前的狀態,下面是幾個比較重要的進程狀態以及它們之間的轉換流程。
點擊查看大圖
void *stack:指向進程內核棧,下面會解釋。
struct mm_struct *mm:與進程地址空間相關的信息都保存在一個叫內存描述符 (memory descriptor) 的結構體 (mm_struct) 中。
點擊查看大圖
pid_t pid:進程標識符,本質就是一個數字,是用戶空間引用進程的唯一標識。
struct task_struct *parent:父進程的 task_struct。
char comm[TASK_COMM_LEN]:進程的名稱。
struct files_struct*files:打開的文件表。
struct signal_struct *signal:信號處理相關。
其他字段,等到有需要的時候再回過頭來學習。
2.2 當發生系統調用或者進程切換時,內核如何找到 task_struct ?
對于 ARM 架構,答案是:通過內核棧 (kernel mode stack)。
為什么要有內核棧?
因為內核是可重入的,在內核中會有多條與不同進程相關聯的執行路徑。因此不同的進程處于內核態時,都需要有自己私有的進程內核棧 (process kernel stack)。
當進程從用戶態切換到內核態時,所使用的棧會從用戶棧切換到內核棧。
至于是如何切換的,關鍵詞是系統調用,這不是本文關注的重點,先放一邊,學習內核要懂得恰當的時候忽略細節。
當發生進程切換時,也會切換到目標進程的內核棧。
同上,關鍵詞是硬件上下文切換 (hardware context switch),忽略具體實現。
無論何時,只要進程處于內核態,就會有內核棧可以使用,否則系統就離崩潰不遠了。
ARM 架構的內核棧和 task_struct 的關系如下:
內核棧的長度是 THREAD_SIZE,對于 ARM 架構,一般是 2 個頁框的大小,即 8KB。
內核將一個較小的數據結構 thread_info 放在內核棧的底部,它負責將內核棧和 task_struct 串聯起來。thread_info 是平臺相關的,在 ARM 架構中的定義如下:
//thread_info.h(archarmincludeasm) structthread_info{ unsignedlongflags;/*lowlevelflags*/ intpreempt_count;/*0=>preemptable,<0?=>bug*/ mm_segment_taddr_limit;/*addresslimit*/ structtask_struct*task;/*maintaskstructure*/ [...] structcpu_context_savecpu_context;/*cpucontext*/ [...] };
thread_info 保存了一個進程能被調度執行的最底層信息(low level task data),例如struct cpu_context_save cpu_context 會在進程切換時用來保存/恢復寄存器上下文。
內核通過內核棧的棧指針可以快速地拿到 thread_info:
//thread_info.h(includelinux) staticinlinestructthread_info*current_thread_info(void) { //current_stack_pointer是當前進程內核棧的棧指針 return(structthread_info*) (current_stack_pointer&~(THREAD_SIZE-1)); }
然后通過 thread_info 找到 task_struct:
//current.h(includeasm-generic) #definecurrent(current_thread_info()->task)
內核里通過 current 宏可以獲得當前進程的 task_struct。
2.3 task_struct 的分配和初始化
當上層應用使用 fork() 創建進程時,內核會新建一個 task_struct。
進程的創建是個復雜的工作,可以延伸出無數的細節。這里我們只是簡單地了解一下 task_struct 的分配和部分初始化的流程。
fork() 在內核里的核心流程:
dup_task_struct() 做了什么?
至于設置內核棧里做了什么,涉及到了進程的創建與切換,不在本文的關注范圍內,以后再研究了。
3. 實驗:打印 task_struct / thread_info / kernel mode stack
實驗目的:
梳理 task_struct / thread_info / kernel mode stack 的關系。
實驗代碼:
#include
運行效果:
taskmoduleinit insmod3123task_struct(edb42580)/stack(ed46c000~ed474000)/thread_info->task(edb42580) bash2393task_struct(eda13e80)/stack(c9dda000~c9de2000)/thread_info->task(eda13e80) sshd2255task_struct(ee5c9f40)/stack(c9d2e000~c9d36000)/thread_info->task(ee5c9f40) sshd543task_struct(ef15f080)/stack(ee554000~ee55c000)/thread_info->task(ef15f080) systemd1task_struct(ef058000)/stack(ef04c000~ef054000)/thread_info->task(ef058000)
在程序里,我們通過 task_struct 找到 stack,然后通過 stack 找到 thread_info,最后又通過 thread_info->task 找到 task_struct。
4. 相關參考
Linux 內核設計與實現 / 第 3.1 章節
深入理解 Linux 內核 / 3
Linux 內核深度解析 / 2.5.1
深入Linux 內核架構 / 2.3
責任編輯:lq
-
Linux
+關注
關注
87文章
11230瀏覽量
208935 -
多線程
+關注
關注
0文章
277瀏覽量
19923 -
進程
+關注
關注
0文章
202瀏覽量
13947
原文標題:Linux 內核 / 進程管理 / 如何描述一個進程?
文章出處:【微信號:strongerHuang,微信公眾號:strongerHuang】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論