1.2 Linux的基本組成
1.2.1 進程
操作系統中的進程定義為程序執行的一個實例,每個進程都在CPU的虛擬內存中分配地址空間,并且每個進程的地址空間都是相互獨立的。進程地址空間由允許進程使用的全部線性地址組成,每個進程所看到的線性地址集合是不同的,一個進程使用的地址與另外一個進程使用的地址之間沒有關系,內核可以通過增加或刪除某些線性區間來動態修改進程的地址空間。
CPU既可以在用戶模式下運行,也可以在內核模式下運行,當某個程序在用戶模式下運行時,不能直接訪問內核中的數據結構或程序,但是,當程序運行在內核模式時,可以訪問用戶態的數據。對于某個執行的程序,多數的時間都處于用戶模式,只有在需要內核提供服務時才會切換到內核模式,當內核滿足了用戶程序的需求后,再次返回到用戶模式。
Linux系統中傳統調度器對進程分別計算時間片,在進程的所有時間片用盡時,需要重新計算,現在的調度器只考慮進程的等待時間,也就是進程在就緒隊列中已等待的時間。調度器的原理是按所分配的計算能力,向進程提供最大的公正性;每次調用調度器時,會選擇等待時間最長的進程,把CPU提供給該進程,這樣,進程的不公平性不會累積,不公平會均勻地分布到系統的所有進程。
1.2.2 進程間通信
進程之間需要相互協作,在Linux系統中存在各種形式的進程間通信。進程間通信通常的實現方式有通過信號量機制與其他進程進行同步、向其他進程發送消息、從其他進程接收消息以及與其他進程共享一段內存區。IPC數據結構是在進程請求IPC資源(信號量、消息隊列或者共享內存)時動態創建的,三種進程間通信的共同點是都使用了全系統范圍的資源,該資源可由幾個進程同時共享。由于一個進程可能需要同類型的多個IPC資源,因此每個新資源都使用一個IPC關鍵字來標識。
IPC信號量與內核信號量非常類似,除此之外與內核信號量沒有任何關系,信號量不作為用于支持原子操作預定義操作的簡單類型變量,而是一整套信號量,可以允許多個操作同時進行。
消息隊列是指進程彼此之間可以通過IPC消息進行通信,進程產生的每條消息都被發送到一個IPC消息隊列中,該消息一直存放在隊列中直到另一個進程將該消息讀走。產生消息并將其寫入隊列的進程稱為發送方,其他進程則從消息隊列中獲取該消息。該消息包含消息正文和一個整數,數字用于標識該消息,接收方可以根據數字搜索消息,消息讀取后,內核從隊列中刪除該消息,只能有一個進程接收一條給定的消息。
共享內存是允許兩個或多個進程把公共數據放入一個共享內存區來進行訪問,如果進程要訪問存放在該共享內存區的數據,必須在自己的地址空間增加一個新的內存區,該內存將映射與共享內存區相關的頁框,這樣的頁框可以方便地由內核通過請求調頁進程處理。
1.2.3 內存管理
內存管理是內核中最重要同時也是最復雜的部分,需要處理器和內核之間的協作,內核在啟動時通過調用start_kernel()函數實現內存結構的初始化工作,之后內存管理的工作交由伙伴系統算法承擔。伙伴算法采用頁框作為基本內存區,適合于大塊內存的請求,但是當有小內存區的請求時(幾十或幾百字節),分配一整個頁框是一種浪費,因此引入了新的數據結構來描述在同一頁框內分配小內存區。
伙伴系統支持按頁分配內存,如果需要分配較小的空間,分配一個或多個頁框的空間,這樣非常浪費空間,比較好的解決方法是將頁框拆分成較小的單位。Linux內核采用了一種稱為“slab”的緩沖分配和管理方法,通過建立slab緩沖,內核能夠儲備一些對象,供后續使用。slab分配器將釋放的內存塊保存在一個內部列表中,而不是立刻返回給伙伴系統,這樣內核不必使用伙伴系統算法,縮短了處理的時間;其次,由于該內存塊仍然是新的,其駐留在CPU高速緩存的概率較高。
由于slab過于復雜,并且本身的管理結構也需要占用過多的內存,同時效率也相對較低,因此出現了slub分配器,slub分配器提供與slab一致的接口,不僅簡化了slab分配器,而且提供了更好的性能。
1.2.4 設備驅動
根據設備驅動程序的基本特性,設備文件可以分為塊設備與字符設備,塊設備的數據可以隨機訪問,如硬盤、CD-ROM驅動器等,對于字符設備的數據則不可以隨機訪問;設備文件是存放在文件系統中的實際文件,其索引節點不包含指向磁盤上數據塊的指針,但是必須包含硬件設備的標識符,對應字符或塊設備文件。
由于塊設備層的設計導致需要持續地調整塊設備的速率及工作方式,因此塊設備驅動程序要比字符設備復雜得多。塊設備的主要特點是CPU和總線讀/寫數據所耗費的時間與磁盤硬件的速度不匹配;塊設備的平均訪問時間長,這是因為磁盤控制器必須在磁盤表面將磁頭移動到存儲數據的準確位置。
驅動程序通過一組固定的接口與內核代碼通信,而擴展設備則通過設備驅動程序處理,因此擴展設備/驅動程序對內核的代碼沒有影響;內核代碼與總線驅動程序的關系比與具體設備驅動程序的關系更為密切。此外,由于不同總線系統之間使用的硬件技術差異較大,因此總線驅動程序向相關的設備驅動程序提供功能和選項的方式不存在標準的接口。
1.2.5 中斷
Linux內核中的中斷通常分為同步中斷和異步中斷,同步中斷是CPU本身在執行程序過程中由CPU控制單元產生的,而異步中斷則是由其他硬件設備隨機產生的;不同設備對應的中斷不同,每個中斷通過一個唯一的數字標識,因此使得內核能夠對中斷進行區別,這樣內核能給不同的中斷提供不同的中斷處理程序。
1.2.6 時鐘
時鐘中斷源能周期地向CPU發出中斷,內核在中斷處的例程中檢查當前進程時間片是否到期,為調度器提供時鐘源。此外,內核根據RTC獲取到起始時間后,依此來維護內核時間,由于RTC計時的單位是秒,為了獲取精確的時間,內核啟動時從RTC中讀取起始時間,之后在每一次時鐘中斷時,利用起始時間加上中斷周期,可以把時鐘精確到毫秒的級別。后來又出現了TSC(Time Stamp Counter,是CPU的一個寄存器),該寄存器隨著CPU時鐘周期的遞增加1,如果當前的CPU主頻為1GHz,則該寄存器每納秒加1。內核以RTC為基礎,每次時鐘中斷通過匯編指令rdtsc讀取TSC,內核在時鐘中斷中通過TSC能夠計算出兩次時鐘中斷間流逝的精確時間,這樣時間能夠精確到納秒的級別。
1.2.7 文件系統
每種操作系統至少都有一種“標準文件系統”,提供了某些功能可以可靠地執行特定的任務,Linux附帶的ext2/3文件系統是一種標準文件系統,該文件系統經證實是健壯的,同時Linux還提供了備選的方案。
為了支持各種本機文件系統,并且同時允許訪問其他操作系統的文件,Linux內核在用戶進程和文件系統實現之間提供了一個抽象層,稱為虛擬文件系統(VFS,Virtual File System),一方面用來提供一種文件、目錄及其他對象操作的統一方法,另一方面能夠與各種方法給出的具體文件系統的實現達成妥協。如圖1-2所示為虛擬文件系統的示意圖。

圖1-2 虛擬文件系統的示意圖
1.2.8 內核模塊
內核中的模塊是一種向Linux內核添加設備驅動、文件系統及其他組件的有效方法。模塊無須重啟系統,通過使用模塊,內核的開發者可以將實驗性的代碼打包到模塊,模塊可以卸載也可以重新安裝,可以無縫地插入內核。在模塊需要卸載時,可以與內核剩余部分相關聯。