《深入理解Linux核心3rd》學習筆記——進程描述符

來源:互聯網
上載者:User

  進程描述符(Process Descriptor),顧名思義,就是進程的描述,即用來描述進程的資料結構,可以理解為進程的屬性。比如進程的狀態、進程的標識(PID)等,都被封裝在了進程描述符這個資料結構中,該資料結構被定義為task_struct。

 

進程狀態

  Linux中的進程有7種狀態,進程的task_struct結構的state欄位指明了該進程的狀態。

可運行狀態(TASK_RUNNING)

可中斷的等待(TASK_INTERRUPTIBLE)

不可中斷的等待(TASK_UNINTERRUPTIBLE)

暫停狀態(TASK_STOPPED)

跟蹤狀態(TASK_TRACED):進程被調試器暫停或監視。

僵死狀態(EXIT_ZOMBIE):進程被終止,但父進程未調用wait類系統調用。

僵死撤銷狀態(TASK_DEAD):父進程發起wait類系統調用,進程由系統刪除。

 

標識一個進程

  標識進程的兩種方法:進程描述符地址、PID。PID的值儲存在task_struct結構的pid欄位中。

  能夠被獨立調度的執行內容都有自己的進程描述符,因此,輕量級進程(LWP)也有自己的task_struct結構。

  Linux把不同的PID分配給每個進程和LWP(類似地,Windows中也是將PID和TID分配給每個進程和線程,且PID和TID不會相同,注,這裡Linux中的LWP類似於Windows中的線程)。

  Linux中還有線程組的概念,一個線程組的所有線程使用該線程組領頭線程的PID,即該組中第一個LWP的PID。這個線程組的PID儲存在task_struct結構的tpid欄位中,線程組領頭線程的tpid和pid的值相同。

 

得到進程描述符地址

  Linux中,有2個資料結構被緊湊地放在了一起:進程的核心堆棧,thread_info(線程描述符)。一般地,這兩個資料結構大小為8192個位元組,放在兩個連續的頁面中,首地址為213的倍數。8KB對於核心堆棧和thread_info來說已經足夠了(也可以在編譯核心時設定,讓這兩個資料結構佔用一個頁面)。這個8KB的起始存放thread_info結構,核心堆棧從末端向下增長。在thread_info結構中,有一個指向進程描述符的指標task,利用該指標可以找到task_struct結構地址。在task_struct結構中,也有一個thread_info指標,指向thread_info結構。

  因為thread_info和核心堆棧被緊湊地存放在一起,因此,可以從核心堆棧找到thread_info結構地址,繼而通過thread_info結構的task指標找到task_struct結構指標。對於8KB而言,得到esp中的值,然後將該值與上0xffffe000,即將低13位清零,就得到了thread_info的地址,然後就可以得到task_struct的地址。

 

進程鏈表

  Linux中將多個進程組織成迴圈雙鏈表的結構,進程鏈表頭是init_task描述符,即0進程或swapper進程的描述符。通過task_struct結構中tasks欄位,將多個進程串連成鏈表的結構。

  早期的Linux版本中,把所有TASK_RUNNING狀態的進程放在一個運行隊列中,這樣,按照優先順序排序該鏈表的開銷比較大,早期的發送器不得不遍曆整個鏈表來選擇最佳的進程。

  Linux 2.6中的運行隊列不同,系統中建立了多個可運行進程鏈表,即運行隊列中包含多個可運行進程鏈表。每個可運行進程鏈表對應一個優先順序,優先順序取值為0~139。假定某個進程優先順序為k,那麼該進程的task_struct結構中run_list欄位就將其串連到優先順序為k的可運行進程鏈表中。另外,在多處理器系統中,每個CPU都有它自己的運行隊列。這麼多可運行進程鏈表由prio_array_t資料結構來管理。

 

進程間關係

  進程之間有父子關係,如果一個進程建立多個子進程,那這些子進程之間就有了兄弟關係。Linux中,進程0和進程1由核心建立,進程1(init)是其他所有進程的祖先。

  在進程描述符表task_struct結構中,以下欄位表示進程間的關係:

real_parent:指向建立進程P的進程的描述符,如果P的父進程不存在,就指向進程1的描述符。

parent:指向P的當前父進程,往往與real_parent一致。當出現Q進程向P發出跟蹤調試ptrace()系統調用時,該欄位指向Q進程描述符。

children:一個鏈表頭,鏈表中所有元素都是進程P建立的子進程。

sibling:指向兄弟進程鏈表的下一個元素或前一個元素的指標。

 

  另外,進程間還存在其他關係:登入工作階段關係、進程組關係、線程組關係、跟蹤調試關係。

  在task_struct結構中,以下欄位表示這些關係(假設當前進程為P):

group_leader:P所在進程組的領頭進程的描述符指標

signal->pgrp:P所在進程組的領頭進程的PID

tgid:P所線上程組的領頭進程的PID

signal->session:P所在登入工作階段領頭進程的PID

ptrace_children:一個鏈表頭,鏈表中的所有元素是被調試器程式跟蹤的P的子進程

ptrace_list:當P被調試跟蹤時,指向調試跟蹤進程的父進程鏈表的前一個和下一個元素

 

PID匯出進程描述符

  有些情況需要從PID得到響應的進程描述符指標,比如kill()系統調用。由於順序掃描進程鏈表並檢查進程描述符的pid欄位是比較低效的,因此引入了4個雜湊表:

PIDTYPE_PID

PIDTYPE_TGID

PIDTYPE_PGID

PIDTYPE_SID

  這四個雜湊表在核心初始化時動態地分配空間,它們的地址被存入pid_hash數組,其長度依賴於RAM容量。利用pid_hashfn可以將PID轉化為表索引。

  為了防止出現雜湊運算帶來的衝突,Linux採用拉鏈法來解決,即引入具有鏈表的雜湊表來處理。

 

進程組織

  運行隊列的鏈表把TASK_RUNNING狀態的所有進程組織在一起。對於其他狀態的進程,Linux做如下處理:

  • TASK_STOPPED、EXIT_ZOMBIE、EXIT_DEAD狀態的進程,Linux並沒有為它們建立專門的鏈表,因為訪問簡單。
  • TASK_INTERRUPTIBLE、TASK_UNINTERRUPTIBLE狀態的進程被分為很多類,每一類對應一個特定的事件。在這種狀態下,進程狀態無法提供足夠的資訊來快速的得到進程,因此引入額外的進程鏈表是必要的。這些鏈表稱為“等待隊列”。

  等待隊列的用途很多,比如中斷處理、進程同步、定時等。

  等待隊列由雙鏈表實現,每個等待隊列都有一個隊頭,這是一個wait_queue_head_t的資料結構。該資料結構中有一個spinlock_t類型的lock變數,這是一個自旋鎖,用來保證等待隊列被互斥的訪問和操作。

  等待隊列中元素的類型是wait_queue_t,該資料結構中有一個task欄位,是一個進程描述符的指標;有一個func欄位,是一個函數指標,表示進程的如何喚醒(即喚醒時調用該函數);還有一個flags欄位,決定了相關進程是互斥進程(flags = 1)還是非互斥進程(flags = 0)。

  這裡解釋下互斥進程與非互斥進程。非互斥進程總是由核心在事件發生時喚醒;互斥進程則是由核心在事件發生時有選擇地喚醒,比如訪問臨界區的進程。

 

進程資源限制

  每個進程都有一組相關的資源限制,指明了進程能夠使用的系統資源數量。避免進程過度使用系統資源(CPU、磁碟空間等)。

  進程資源的限制存放在進程描述符的signal->rlim欄位中,該欄位是一個類型為rlimit結構的數組,數組中每個元素對應一種資源。

  用getrlimit()和setrlimit()系統調用,使用者能夠增加當前資源限制的上限。

  如果資源限制值為RLIMIT_INFINITY(0xffffffff),就意味著沒有對應的資源限制。

 

總結

  進程描述符(task_struct)某些欄位含義,假設進程為P。

  • state:P進程狀態,用set_task_state和set_current_state宏更改之,或直接賦值。
  • thread_info:指向thread_info結構的指標。
  • run_list:假設P狀態為TASK_RUNNING,優先順序為k,run_list將P串連到優先順序為k的可運行進程鏈表中。
  • tasks:將P串連到進程鏈表中。
  • ptrace_children:鏈表頭,鏈表中的所有元素是被調試器程式跟蹤的P的子進程。
  • ptrace_list:P被調試時,鏈表中的所有元素是被調試器程式跟蹤的P的子進程。
  • pid:P進程標識(PID)。
  • tgid:P所在的線程組的領頭進程的PID。
  • real_parent:P的真實的父進程的進程描述符指標。
  • parent:P的父進程的進程描述符指標,當被調試時就是調試器進程的描述符指標。
  • children:P的子進程鏈表。
  • sibling:將P串連到P的兄弟進程鏈表。
  • group_leader:P所在的線程組的領頭進程的描述符指標。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.