linux kernel 學習筆記二 進程管理

一、進程和線程

說到操作系統就不得不提的兩個概念。進程就是出於執行期的程序以及相關的資源(打開的文件、掛起的信號、內核內部的數據、處理器狀態等)的總稱。線程,是在進程中活動的對象,每個線程都擁有一個獨立地程序計數器、進程棧和一組進程寄存器。有關進程和線程的關係,可以參考下這篇博文,說得非常形象:
http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html
但是,linux系統中對線程的實現非常特別:它對線程和進程並不特別區分。對linux而言,線程只不過是一種特殊的進程罷了。

二、進程描述符及任務結構

內核把進程的列表存放在叫任務隊列(task list)的雙向鏈表中。鏈表的每一項都是類型爲task_struct、稱爲進程描述符(process descriptor)的結構,該結構定義在<linux/sched.h>文件中。進程描述符中包含一個具體進程的所有信息。task_struct源碼比較長,想了解的可以移步:http://blog.csdn.net/hongchangfirst/article/details/7075026

1、線程描述符:
對每個進程,linux內核都把兩個不同的數據結構緊湊地存放在一個單獨爲進程分配的內存區域中,一個是內核態的進程堆棧,另一個是緊挨着進程描述符的小數據結構thread_info,也叫線程描述符。





在這個圖中,esp寄存器是CPU棧指針,用來存放棧頂單元的地址。一旦數據寫入堆棧,esp的值就遞減。3.16的內核源碼中,struct thread_info 定義如下:

struct thread_info {
          struct task_struct      *task;          /* main task structure */
          struct exec_domain      *exec_domain;   /* execution domain */
          __u32                   flags;          /* low level flags */
          __u32                   status;         /* thread synchronous flags */
          __u32                   cpu;            /* current CPU */
          int                     saved_preempt_count;
          mm_segment_t            addr_limit;
          struct restart_block    restart_block;
          void __user             *sysenter_return;
          unsigned int            sig_on_uaccess_error:1;
          unsigned int            uaccess_err:1;  /* uaccess failed */
  };

2、進程描述符的存放:
內核通過一個唯一的進程標識值(process identification value)或PID值來標識每個進程。PID是一個數,表示爲pid_t了性,實際上就是一個int型。PID默認最大值是32768(short int最大值),儘管也可以高達400萬。如果需要的話,可以由系統管理員通過修改/proc/sys/kernel/pid_max來提高上限。
在內核中,訪問任務通常要獲得指向其task_struct的指針。可以通過current宏查找到當前正在運行的進程描述符。像x86這種體系結構(寄存器不富裕),只能在內核棧的尾端創建thread_info結構,通過計算偏移間接地查找task_struct結構。

  1. #define get_current() (current_thread_info()->task)
  2. #define current get_current()
最後current再從thread_info的task域中提取並返回task_struct的地址。
3、進程的狀態
進程描述符中的state描述了進程當前的狀態,進程的狀態包括以下五種:
  • TASK_RUNNING(運行):進程是可執行的。它或者正在執行,或者在運行隊列中等待執行
  • TASK_INTERRUPTIBLE(可中斷):該進程正在睡眠(被阻塞),等待某些條件的達成,一旦這些條件達成,內核就會把該進程設置爲運行。
  • TASK_UNINTERRUPTIBLE(不可中斷):就算是收到信號也不會被喚醒或者準備投入運行,該狀態用的較少。
  • __TASK_TRACED:被其他進程跟蹤的進程,例如通過ptrace對調試程序進行跟蹤。
  • __TASK_STOPPED(停止):進程停止執行;進程沒有投入運行也不能投入運行。通常這種狀態發生在接收到SIGSTOP,SIGTSTP等信號的時候。此外,調試期間受到任何信號,都會是進程進入這種狀態。
4、進程的家族樹
所有的進程都是PID爲1的init進程的後代。內核在系統啓動的最後階段啓動init進程。系統每個進程必有一個父進程,相應的,每個進程也可以擁有零個或多個子進程。擁有同一個父進程的所有進程被稱爲兄弟。進程間關係存放在進程描述符中。每個task_struct都包含一個指向其父進程的task_struct、叫做parent的指針,還包含一個叫做children的子進程鏈表。
三、進程的創建
unix系統的進程創建很特別。許多其它的操作系統都提供了產生(spawn)進程的機制:首先在新的地址空間創建進程,讀入可執行文件,最後開始執行。unix採用了與衆不同的實現方式,它把上述步驟分解到兩個單獨的函數中去執行:fork()和exec()。首先,fork()通過拷貝當前進程創建一個子進程。子進程與父進程的區別僅在於PID,PPID(父進程的進程號,子進程將其設置爲被拷貝進程的PID)和某些資源統計量(如掛起的信號)。exec()函數負責讀取可執行文件並將其載入地址空間開始運行。
想進一步瞭解可以參考:http://en.wikipedia.org/wiki/Fork-exec 或者 http://www.cnblogs.com/hicjiajia/archive/2011/01/20/1940154.html






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章