
(1)可運行狀態處于這種狀態的進程,要么正在運行、要么正準備運行。正在運行的進程就是當前進程(由current 宏 所指向的進程),而準備運行的進程只要得到CPU 就可以立即投入運行,CPU 是這些進程唯一等待的系統資源。系統中有一個運行隊列(run_queue),用來容納所有處于可運行狀態的進程,調度程序執行時,從中選擇一個進程投入運行。當前運行進程一直處于該隊列中,也就是說,current總是指向運行隊列中的某個元素,只是具體指向誰由調度程序決定。(2)等待狀態處于該狀態的進程正在等待某個事件(Event)或某個資源,它肯定位于系統中的某個等待隊列(wait_queue)中。Linux 中處于等待狀態的進程分為兩種:可中斷的等待狀態和不可中斷的等待狀態。處于可中斷等待態的進程可以被信號喚醒,如果收到信號,該進程就從等待狀態進入可運行狀態,并且加入到運行隊列中,等待被調度;而處于不可中斷等待態的進程是因為硬件環境不能滿足而等待,例如等待特定的系統資源,它任何情況下都不能被打斷,只能用特定的方式來喚醒它,例如喚醒函數wake_up()等。(3)暫停狀態此時的進程暫時停止運行來接受某種特殊處理。通常當進程接收到SIGSTOP、SIGTSTP、SIGTTIN 或 SIGTTOU 信號后就處于這種狀態。例如,正接受調試的進程就處于這種狀態。(4)僵死狀態進程雖然已經終止,但由于某種原因,父進程還沒有執行wait()系統調用,終止進程的信息也還沒有回收。顧名思義,處于該狀態的進程就是死進程,這種進程實際上是系統中的垃圾,必須進行相應處理以釋放其占用的資源。A child that terminates, but has not been waited for becomes a "zombie". The kernel maintains a minimal set of information about the zombie PRocess (PID, termination status, resource usage information) in order to allow the parent to later perform a wait to obtain information about the child. As long as a zombie is not removed from the system via a wait, it will consume a slot in the kernel process table, and if this table fills, it will not be possible to create further processes. If a parent process terminates, then its "zombie" children (if any) are adopted by init(8), which automatically performs a wait to remove the zombies.2.進程調度信息調度程序利用這部分信息決定系統中哪個進程最應該運行,并結合進程的狀態信息保證系統運轉的公平和高效。這一部分信息通常包括進程的類別(普通進程還是實時進程)、進程的優先級等,如表4.2 所示。
當need_resched 被設置時,在“下一次的調度機會”就調用調度程序schedule();counter 代表進程剩余的時間片,是進程調度的主要依據,也可以說是進程的動態優先級,因為這個值在不斷地減少;nice 是進程的靜態優先級,同時也代表進程的時間片,用于對counter 賦值,可以用nice()系統調用改變這個值;policy是適用于該進程的調度策略,實時進程和普通進程的調度策略是不同的;rt_priority 只對實時進程有意義,它是實時進程調度的依據。進程的調度策略有3 種,如表4.3 所示。
只有root 用戶能通過sched_setscheduler()系統調用來改變調度策略。3.標識符(Identifiers)每個進程有進程標識符、用戶標識符、組標識符,如表4.4 所示。不管對內核還是普通用戶來說,怎么用一種簡單的方式識別不同的進程呢?這就引入了進程標識符(PID,process identifier),每個進程都有一個唯一的標識符,內核通過這個標識符來識別不同的進程,同時,進程標識符PID 也是內核提供給用戶程序的接口,用戶程序通過PID 對進程發號施令。PID 是32 位的無符號整數,它被順序編號:新創建進程的PID通常是前一個進程的PID 加1。然而,為了與16 位硬件平臺的傳統Linux 系統保持兼容,在Linux 上允許的最大PID 號是32767,當內核在系統中創建第32768 個進程時,就必須重新開始使用已閑置的PID 號。
4.進程通信有關信息(ipC,Inter_Process Communication)為了使進程能在同一項任務上協調工作,進程之間必須能進行通信即交流數據。Linux 支持多種不同形式的通信機制。它支持典型的UNIX 通信機制(IPC Mechanisms):信號(Signals)、管道(Pipes),也支持System V / Posix 通信機制:共享內存(Shared Memory)、信號量和消息隊列(Message Queues),如表4.5 所示。
5.進程鏈接信息(Links)程序創建的進程具有父/子關系。因為一個進程能創建幾個子進程,而子進程之間有兄弟關系,在task_struct 結構中有幾個域來表示這種關系。在Linux 系統中,除了初始化進程init,其他進程都有一個父進程(Parent Process)。可以通過fork()或clone()系統調用來創建子進程,除了進程標識符(PID)等必要的信息外,子進程的task_struct 結構中的絕大部分的信息都是從父進程中拷貝。系統有必要記錄這種“親屬”關系,使進程之間的協作更加方便,例如父進程給子進程發送殺死(kill)信號、父子進程通信等。每個進程的task_struct 結構有許多指針,通過這些指針,系統中所有進程的task_struct結構就構成了一棵進程樹,這棵進程樹的根就是初始化進程init的task_struct結構(init 進程是Linux 內核建立起來后人為創建的一個進程,是所有進程的祖先進程)。表4.6 是進程所有的鏈接信息。
6.時間和定時器信息(Times and Timers)一個進程從創建到終止叫做該進程的生存期(lifetime)。進程在其生存期內使用CPU的時間,內核都要進行記錄,以便進行統計、計費等有關操作。進程耗費CPU 的時間由兩部分組成:一是在用戶模式(或稱為用戶態)下耗費的時間、一是在系統模式(或稱為系統態)下耗費的時間。每個時鐘滴答,也就是每個時鐘中斷,內核都要更新當前進程耗費CPU 的時間信息。
7.文件系統信息(File System)進程可以打開或關閉文件,文件屬于系統資源,Linux 內核要對進程使用文件的情況進行記錄。task_struct 結構中有兩個數據結構用于描述進程與文件相關的信息。其中,fs_struct 中描述了兩個VFS 索引節點(VFS inode),這兩個索引節點叫做root 和pwd,分別指向進程的可執行映像所對應的根目錄(Home Directory)和當前目錄或工作目錄。file_struct 結構用來記錄了進程打開的文件的描述符(Descriptor)。如表4.9 所示。
在文件系統中,每個VFS 索引節點唯一描述一個文件或目錄,同時該節點也是向更低層的文件系統提供的統一的接口。8.虛擬內存信息(Virtual Memory)除了內核線程(Kernel Thread),每個進程都擁有自己的地址空間(也叫虛擬空間),用mm_struct 來描述。另外Linux 2.4 還引入了另外一個域active_mm,這是為內核線程而引入的。因為內核線程沒有自己的地址空間,為了讓內核線程與普通進程具有統一的上下文切換方式,當內核線程進行上下文切換時,讓切換進來的線程的active_mm 指向剛被調度出去的進程的mm_struct。內存信息如表4.10 所示。
9.頁面管理信息當物理內存不足時,Linux 內存管理子系統需要把內存中的部分頁面交換到外存,其交換是以頁為單位的。有關頁面的描述信息如表4.11。
10.對稱多處理機(SMP)信息Linux 2.4 對SMP 進行了全面的支持,表4.12 是與多處理機相關的幾個域。
11.和處理器相關的環境(上下文)信息(Processor Specific Context)這里要特別注意標題:和“處理器”相關的環境信息。進程作為一個執行環境的綜合,當系統調度某個進程執行,即為該進程建立完整的環境時,處理器(Processor)的寄存器、堆棧等是必不可少的。因為不同的處理器對內部寄存器和堆棧的定義不盡相同,所以叫做“和處理器相關的環境”,也叫做“處理機狀態”。當進程暫時停止運行時,處理機狀態必須保存在進程的thread_struct 結構(多線程的話每個線程都有一份)中,當進程被調度重新運行時再從中恢復這些環境,也就是恢復這些寄存器和堆棧的值。處理機信息如表4.13 所示。
12.其他(1)struct wait_queue *wait_chldexit在進程結束時,或發出系統調用wait 時,為了等待子進程的結束,而將自己(父進程)睡眠在該等待隊列上,設置狀態標志為TASK_INTERRUPTIBLE,并且把控制權轉給調度程序。(2)Struct rlimit rlim[RLIM_NLIMITS]每一個進程可以通過系統調用setrlimit 和getrlimit 來限制它資源的使用。(3)Int exit_code exit_signal程序的返回代碼以及程序異常終止產生的信號,這些數據由父進程(子進程完成后)輪流查詢。(4)Char comm[16]這個域存儲進程執行的程序的名字,這個名字用在調試中。(5)Unsigned long personalityLinux 可以運行X86 平臺上其他UNIX 操作系統生成的符合iBCS2 標準的程序,personality 進一步描述進程執行的程序屬于何種UNIX 平臺的“個性”信息。通常有PER_Linux,PER_Linux_32BIT,PER_Linux_EM86,PER_SVR4,PER_SVR3,PER_SCOSVR3,PER_WYSEV386,PER_ISCR4,PER_BSD,PER_XENIX 和PER_MASK 等,參見include/Linux/personality.h>。(6) int did_exec:1按POSIX 要求設計的布爾量,區分進程正在執行老程序代碼,還是用系統調用execve()裝入一個新的程序。(7)struct linux_binfmt *binfmt指向進程所屬的全局執行文件格式結構,共有a.out、script、elf、java 等4 種。新聞熱點
疑難解答