Linux 核心剖析

風靈使發表於2018-11-13

由於本文的目標是對 Linux 核心進行介紹並探索其體系結構和主要元件,因此首先回顧一下 Linux 的簡短歷史,然後從較高的層次審視 Linux 核心的體系結構,最後介紹它的主要子系統。Linux 核心具有超過 600 萬行的程式碼,因此本文不可能進行完整的介紹。請使用指向其他內容的連結進一步學習。

Linux 的簡短歷史

儘管 Linux 絕對是最流行的開源作業系統,但是相對於其他作業系統的漫長曆史來說,Linux 的歷史非常短暫。在計算機出現早期,程式設計師是使用硬體語言在裸硬體上進行開發的。缺少作業系統就意味著在某個時間只有一個應用程式(和一個使用者)可以使用這些龐大而又昂貴的裝置。早期的作業系統是在 20 世紀 50 年代開發的,用來提供簡單的開發體驗。包括為 IBM 701 開發的 General Motors Operating System(GMOS)和 North American Aviation 為 IBM 709 開發的 FORTRAN Monitor System(FMS)。

在 20 世紀 60 年代,MIT(Massachusetts Institute of Technology)和一些公司為 GE-645 開發了一個名為 Multics(Multiplexed Information and Computing Service)的實驗性的作業系統。這個作業系統的開發者之一 AT&T 後來退出了 Multics,並在 1970 年開發了自己的名為 Unics 的作業系統。與這個作業系統一同誕生的是 C 語言,C 語言就是為此而開發的,然後它們使用 C 語言對作業系統進行了重寫,使作業系統開發具有可移植性。

二十年後,Andrew Tanenbaum 建立了一個微核心版本的 UNIX®,名為 MINIX(代表 minimal UNIX),它可以在小型的個人計算機上執行。這個開源作業系統在 20 世紀 90 年代激發了 Linus Torvalds 開發 Linux 的靈感(請參看圖 1 所示)。
圖 1. 主要 Linux 核心發行版簡史
主要 Linux 核心發行版簡史

Linux 快速從一個個人專案進化成為一個全球數千人蔘與的開發專案。對於 Linux 來說,最為重要的決策之一是採用 GPL(GNU General Public License)。在 GPL 保護之下,Linux 核心可以防止商業使用,並且它還從 GNU 專案(Richard Stallman 開發,其原始碼要比 Linux 核心大得多)的使用者空間開發受益。這允許使用一些非常有用的應用程式,例如 GCC(GNU Compiler Collection)和各種 shell 支援。

Linux 核心簡介

現在讓我們從一個比較高的高度來審視一下 GNU/Linux 作業系統的體系結構。您可以從兩個層次上來考慮作業系統,如圖 2 所示。
圖 2. GNU/Linux 作業系統的基本體系結構
GNU/Linux 作業系統的基本體系結構

最上面是使用者(或應用程式)空間。這是使用者應用程式執行的地方。使用者空間之下是核心空間,Linux 核心正是位於這裡。

GNU C Libraryglibc)也在這裡。它提供了連線核心的系統呼叫介面,還提供了在使用者空間應用程式和核心之間進行轉換的機制。這點非常重要,因為核心和使用者空間的應用程式使用的是不同的保護地址空間。每個使用者空間的程式都使用自己的虛擬地址空間,而核心則佔用單獨的地址空間。 更多資訊,請參看 參考資料 一節中的連結。

Linux 核心可以進一步劃分成 3 層。最上面是系統呼叫介面,它實現了一些基本的功能,例如 readwrite。系統呼叫介面之下是核心程式碼,可以更精確地定義為獨立於體系結構的核心程式碼。這些程式碼是 Linux 所支援的所有處理器體系結構所通用的。在這些程式碼之下是依賴於體系結構的程式碼,構成了通常稱為 BSP(Board Support Package)的部分。這些程式碼用作給定體系結構的處理器和特定於平臺的程式碼。

Linux 核心的屬性

在討論大型而複雜的系統的體系結構時,可以從很多角度來審視系統。體系結構分析的一個目標是提供一種方法更好地理解原始碼,這正是本文的目的。

Linux 核心實現了很多重要的體系結構屬性。在或高或低的層次上,核心被劃分為多個子系統。Linux 也可以看作是一個整體,因為它會將所有這些基本服務都整合到核心中。這與微核心的體系結構不同,後者會提供一些基本的服務,例如通訊、I/O、記憶體和程式管理,更具體的服務都是插入到微核心層中的。每種核心都有自己的優點,不過這裡並不對此進行討論。

隨著時間的流逝,Linux 核心在記憶體和 CPU 使用方面具有較高的效率,並且非常穩定。但是對於 Linux 來說,最為有趣的是在這種大小和複雜性的前提下,依然具有良好的可移植性。Linux 編譯後可在大量處理器和具有不同體系結構約束和需求的平臺上執行。一個例子是 Linux 可以在一個具有記憶體管理單元(MMU)的處理器上執行,也可以在那些不提供 MMU 的處理器上執行。Linux 核心的 uClinux 移植提供了對非 MMU 的支援。更詳細資訊請參看 參考資料 一節的內容。

Linux 核心的主要子系統

現在使用圖 3 中的分類說明 Linux 核心的主要元件。
圖 3. Linux 核心的一個體繫結構透檢視
Linux 核心的一個體繫結構透檢視

系統呼叫介面

SCI 層提供了某些機制執行從使用者空間到核心的函式呼叫。正如前面討論的一樣,這個介面依賴於體系結構,甚至在相同的處理器家族內也是如此。SCI 實際上是一個非常有用的函式呼叫多路複用和多路分解服務。在 ./linux/kernel 中您可以找到 SCI 的實現,並在 ./linux/arch 中找到依賴於體系結構的部分。有關這個元件的更詳細資訊可以在 參考資料 一節中找到。

程式管理

程式管理的重點是程式的執行。在核心中,這些程式稱為執行緒,代表了單獨的處理器虛擬化(執行緒程式碼、資料、堆疊和 CPU 暫存器)。在使用者空間,通常使用程式 這個術語,不過 Linux 實現並沒有區分這兩個概念(程式和執行緒)。核心通過 SCI 提供了一個應用程式程式設計介面(API)來建立一個新程式(fork、exec 或 Portable Operating System Interface [POSIX] 函式),停止程式(kill、exit),並在它們之間進行通訊和同步(signal 或者 POSIX 機制)。

程式管理還包括處理活動程式之間共享 CPU 的需求。核心實現了一種新型的排程演算法,不管有多少個執行緒在競爭 CPU,這種演算法都可以在固定時間內進行操作。這種演算法就稱為 O(1) 排程程式,這個名字就表示它排程多個執行緒所使用的時間和排程一個執行緒所使用的時間是相同的。 O(1) 排程程式也可以支援多處理器(稱為對稱多處理器或 SMP)。您可以在 ./linux/kernel 中找到程式管理的原始碼,在 ./linux/arch 中可以找到依賴於體系結構的原始碼。在 參考資料 一節中可以瞭解有關這個演算法的更多內容。

記憶體管理

核心所管理的另外一個重要資源是記憶體。為了提高效率,如果由硬體管理虛擬記憶體,記憶體是按照所謂的記憶體頁 方式進行管理的(對於大部分體系結構來說都是 4KB)。Linux 包括了管理可用記憶體的方式,以及物理和虛擬對映所使用的硬體機制。

不過記憶體管理要管理的可不止 4KB 緩衝區。Linux 提供了對 4KB 緩衝區的抽象,例如 slab 分配器。這種記憶體管理模式使用 4KB 緩衝區為基數,然後從中分配結構,並跟蹤記憶體頁使用情況,比如哪些記憶體頁是滿的,哪些頁面沒有完全使用,哪些頁面為空。這樣就允許該模式根據系統需要來動態調整記憶體使用。

為了支援多個使用者使用記憶體,有時會出現可用記憶體被消耗光的情況。由於這個原因,頁面可以移出記憶體並放入磁碟中。這個過程稱為交換,因為頁面會被從記憶體交換到硬碟上。記憶體管理的原始碼可以在 ./linux/mm 中找到。

虛擬檔案系統

虛擬檔案系統(VFS)是 Linux 核心中非常有用的一個方面,因為它為檔案系統提供了一個通用的介面抽象。VFS 在 SCI 和核心所支援的檔案系統之間提供了一個交換層(請參看圖 4)。
圖 4. VFS 在使用者和檔案系統之間提供了一個交換層
VFS 在使用者和檔案系統之間提供了一個交換層

在 VFS 上面,是對諸如 open、close、read 和 write 之類的函式的一個通用 API 抽象。在 VFS 下面是檔案系統抽象,它定義了上層函式的實現方式。它們是給定檔案系統(超過 50 個)的外掛。檔案系統的原始碼可以在 ./linux/fs 中找到。

檔案系統層之下是緩衝區快取,它為檔案系統層提供了一個通用函式集(與具體檔案系統無關)。這個快取層通過將資料保留一段時間(或者隨即預先讀取資料以便在需要是就可用)優化了對物理裝置的訪問。緩衝區快取之下是裝置驅動程式,它實現了特定物理裝置的介面。

網路堆疊

網路堆疊在設計上遵循模擬協議本身的分層體系結構。回想一下,Internet Protocol (IP) 是傳輸協議(通常稱為傳輸控制協議或 TCP)下面的核心網路層協議。TCP 上面是 socket 層,它是通過 SCI 進行呼叫的。

socket 層是網路子系統的標準 API,它為各種網路協議提供了一個使用者介面。從原始幀訪問到 IP 協議資料單元(PDU),再到 TCP 和 User Datagram Protocol (UDP),socket 層提供了一種標準化的方法來管理連線,並在各個終點之間移動資料。核心中網路原始碼可以在 ./linux/net 中找到。

裝置驅動程式

Linux 核心中有大量程式碼都在裝置驅動程式中,它們能夠運轉特定的硬體裝置。Linux 原始碼樹提供了一個驅動程式子目錄,這個目錄又進一步劃分為各種支援裝置,例如 Bluetooth、I2C、serial 等。裝置驅動程式的程式碼可以在 ./linux/drivers 中找到。

依賴體系結構的程式碼

儘管 Linux 很大程度上獨立於所執行的體系結構,但是有些元素則必須考慮體系結構才能正常操作並實現更高效率。./linux/arch 子目錄定義了核心原始碼中依賴於體系結構的部分,其中包含了各種特定於體系結構的子目錄(共同組成了 BSP)。對於一個典型的桌面系統來說,使用的是 i386 目錄。每個體系結構子目錄都包含了很多其他子目錄,每個子目錄都關注核心中的一個特定方面,例如引導、核心、記憶體管理等。這些依賴體系結構的程式碼可以在 ./linux/arch 中找到。

Linux 核心的一些有用特性

如果 Linux 核心的可移植性和效率還不夠好,Linux 還提供了其他一些特性,它們無法劃分到上面的分類中。

作為一個生產作業系統和開源軟體,Linux 是測試新協議及其增強的良好平臺。Linux 支援大量網路協議,包括典型的 TCP/IP,以及高速網路的擴充套件(大於 1 Gigabit Ethernet [GbE] 和 10 GbE)。Linux 也可以支援諸如流控制傳輸協議(SCTP)之類的協議,它提供了很多比 TCP 更高階的特性(是傳輸層協議的接替者)。

Linux 還是一個動態核心,支援動態新增或刪除軟體元件。被稱為動態可載入核心模組,它們可以在引導時根據需要(當前特定裝置需要這個模組)或在任何時候由使用者插入。

Linux 最新的一個增強是可以用作其他作業系統的作業系統(稱為系統管理程式)。最近,對核心進行了修改,稱為基於核心的虛擬機器(KVM)。這個修改為使用者空間啟用了一個新的介面,它可以允許其他作業系統在啟用了 KVM 的核心之上執行。除了執行 Linux 的其他例項之外, Microsoft® Windows® 也可以進行虛擬化。惟一的限制是底層處理器必須支援新的虛擬化指令。更多資訊請參看 參考資料 一節的內容。

結束語

本文對 Linux 核心體系結構及其特性和功能進行了簡要介紹。有關核心的詳細內容,可以參考每個 Linux 發行版中附帶的 Documentation 目錄。請一定檢視本文末尾的 參考資料 一節,瞭解有關本文中所討論主題的更詳細資訊。

相關文章