Search Google

Friday, June 20, 2008

[Process Management] Process/Thread Creation Part 3

專門用語:

  • 使用打字機(Courier New)字體表示原始碼。
  • task/process即為Linux中的thread。
  • 文中的Linux與Linux kernel指的皆為作業系統核心。
  • 使用斜體字型標示Linux中的資料結構,macro,變數或函式名稱。
Kernel版本:
  • v2.6.24.3
Kernel thread與User thread建立過程的相同之處:
  • 都會呼叫do_fork函式建立task_structtask_thread_info,與堆疊空間。
  • 新建立的thread的狀態都是可以執行,但不一定馬上被執行。
Kernel thread與User thread建立過程的不同之處:
  • 傳入do_fork的數性參數不同,就連產生user thread的三個函式1本身傳入的屬性參數都不同。
  • 產生kernel thread時新thread要執行的函式已經存在記憶體中,因此可以直接將函數指標存入暫存器2,而產生user thread時Linux需要先呼叫sys_execve函式讀取存放於硬碟的執行檔並將內容放入記憶體中再將函式指標存入暫存器。
建立好新Thread,然後呢? 這個部分要討論的是每個thread被建立出來直到執行完畢有可能經歷的狀態3,Linux將thread的狀態主要分為以下幾種(並附上說明):
  • TASK_RUNNING:擁有此狀態的thread是被放在runqueue中,隨時有可能被scheduler選出來執行。
  • TASK_INTERRUPTIBLE:擁有此狀態的thread並不存在於runqueue中,只有在等待的條件成立或是接收到signal時才會被重新放入runqueue成為可執行的thread。
  • TASK_UNINTERRUPTIBLE:與擁有TASK_INTERRUPTIBLE狀態的thread一樣不存在於runqueue中並等待條件成立,但是該thread並不會因為接收到signal4而被重新放入runqueue等待執行。
  • EXIT_ZOMBIE:當一個thread執行完畢但是它的task_structtask_thread_info與堆疊空間還存在於記憶體中的時候該thread便是此狀態,因此runqueue中當然也找不到該thread。
  • TASK_STOPPED:這個狀態表示一個thread的運行因接收到signal而遭到停止,最好的例子便是進入GDB除錯模式的thread。
每個thread從被建立出來到執行結束都離不開上述幾個狀態,那麼thread的狀態又是在什麼時候改變的呢?請參照下圖(懶得畫,直接節錄自Robert Love 寫的Linux Kernel Development,若有侵權疑慮請告知,我會在看到通知之後替換 ):

上圖中的TASK_ZOMBIE在2.6.24.3裡面其實就是EXIT_ZOMBIE
以下是thread狀態的define值:

#define TASK_RUNNING 0
#define TASK_INTERRUPTIBLE 1
#define TASK_UNINTERRUPTIBLE 2
#define TASK_STOPPED 4
#define TASK_TRACED 8
/* in tsk->exit_state */
#define EXIT_ZOMBIE 16
#define EXIT_DEAD 32
/* in tsk->state again */
#define TASK_DEAD 64

當thread被標示為TASK_TRACED狀態時表示該thread正在被其parent使用ptrace5觀察它的運行,至於EXIT_DEADTASK_DEAD狀態就等我們探討Linux如何移除執行完畢的thread時再好好觀察他們的作用各是什麼。接下來我們要討論當thread進入EXIT_ZOMBIE狀態之後Linux是如何將它移除。



1 sys_forksys_vfork,與sys_clone
2 此指新thread存放暫存器的資料結構,當scheduler挑選新thread執行之前該資料結構中的暫存器內容全部都會被放進真實的暫存器中。
3 紀錄於task_struct中的state欄位。
4 應該說是完全感受不到signal的存在。
5 可以把它看作debug工具的一種(http://linux.about.com/library/cmd/blcmdl2_ptrace.htm )。

No comments: