天天看點

[筆記分享] [OS] Linux的程序管理

Platform: msm8x60

Kernel: 2.6

程序是不局限于一段可執行代碼,還要包括其他資源,如打開的檔案、信号、處理器狀态、位址空間、資料及一個或者多個線程。多個程序可執行同一個程式。多個程序可共享打開的檔案、位址空間之類資源。

線程是程序中的活動對象,每個線程都有獨立的程序棧、程式計數器和寄存器組。兄弟線程間共享位址空間、檔案系統等資源。

程序描述符

核心将程序放在任務隊列雙向循環連結清單中,每項叫task_struct,如下圖。結構描述了一個正在執行程式的所有資訊。

[筆記分享] [OS] Linux的程式管理

Linux通過slab配置設定task_struct,在後面記憶體管理部分會講slab。通過slab能達到避免動态配置設定和釋放鎖帶來的資源消耗。task_struct由于結構太大,是以用圖表示了,如下:

[筆記分享] [OS] Linux的程式管理

為了快速擷取task_struct的位置,Linux在核心棧尾部建立了個新結構struct thread_info。其結構和存放位置如下:

[筆記分享] [OS] Linux的程式管理

每個程序用pid表示,可修改程序最大數目。通路task_struct的方法是通過thread_info計算偏移位址來查找。(thread_info中有task元素)

宏如下:

current_thread_info()->task或者 current 這兩個宏都可以得到目前task_struct位址。

程序狀态

程序通過state域描述目前狀态:

TASK_RUNNING: 程序正在執行,或者在運作隊列中等待執行。

TASK_INTERRUPTIBLE: 程序在睡眠,等待某事件滿足,可在接收到信号後激活。

TASK_UNINTERRUPTIBLE: 程序在睡眠,等待某事件滿足,忽略信号的接收。

TASK_ZOMBIE: 程序已經結束,但父程序沒調用wait4()系統調用。

TASK_STOPED: 程序沒投入運作也不能投入運作。在收到SIGSTOP SIGTSTP等信号時發生,在調試時會處于這種狀态。

程序間狀态轉換如下:

[筆記分享] [OS] Linux的程式管理

設定程序狀态可用set_task_state()函數, 帶記憶體屏障功能。也可用set_current_state()設定目前程序狀态。

當一個程式執行系統調用時,處于核心運作狀态,我們稱為程序上下文。

另外,我們可通過list_entry, list_for_each, for_each_process來周遊程序連結清單,用next_task, pre_task來擷取相鄰程序描述符。

程序建立

和其他系統不一樣,Linux建立程序通過fork()和exec()兩個步驟實作。Fork()拷貝父程序的内容建立,父子程序的差別在于pid, ppid、挂起的信号及某些資源。之後exec()讀取可執行檔案載入位址空間運作。

Fork()采用寫時拷貝的方法,就是說當真在寫入的時候,才進行将位址空間拷貝到子程序。提高了快速執行的能力。

fork()、vfork()、__clone()都是調用clone()來實作程序建立的。Clone()調用do_fork()。主要流程如下:

[筆記分享] [OS] Linux的程式管理

vfork()和fork()的差別在于不拷貝父程序頁表。子程序運作時,父程序阻塞直到子程序給其發送信号。

線程實作

核心把所有線程當程序來看待,隻是傳給clone()的參數有點差別而已。每個線程都有自己的task_struct,隻是它和其他一些線程共享一些資源,如位址空間、檔案系統資源、檔案描述符和信号處理程式。

線程建立:

clone(CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND, 0)

程序建立:

Clone(SIGCHILD, 0)

Vfork()建立:

Clone(CLONE_VFORK|CLONE_VM|SIGCHILD, 0)

核心線程和普通線程的差別在于其沒有獨立的位址空間,它們用的是前一個程序位址空間。不過他們和普通程序一樣,可被排程和搶占。函數如下:

[筆記分享] [OS] Linux的程式管理

程序終結

不管程序如何終結,該任務大部分都要靠do_exit()來完成。代碼如下:

[筆記分享] [OS] Linux的程式管理

至此,和程序相關資源被釋放掉了,程序不可運作處于TASK_ZOMBIE狀态,它所占用資源就是核心棧、thread_info和 task_struct結構。存在的目的是給父程序提供資訊,等父程序檢測到後,剩餘資源都被釋放。

在調用了wait4()系統調用之後,最終會調用release_task()來完成釋放程序描述符剩餘的資源。代碼如下:

[筆記分享] [OS] Linux的程式管理
[筆記分享] [OS] Linux的程式管理

繼續閱讀