從概念到真實系統
你已經爬了很長一段路。一階一階地,你學會了作業系統是什麼、以及它替大家做的那一小組工作:它把許多程式當成行程同時跑、透過排程共享 CPU、藉虛擬記憶體給每個程式一份「自己擁有整片記憶體」的錯覺、並把磁碟藏在一套整潔的檔案系統後頭。這每一樣都是當成概念來教的,多少跟任何一台特定機器是分開的。這最後一階則反過來做:它指向你實際在用的那些真實作業系統,問你學過的每個概念跑到哪裡去了。
先問一個問題會有幫助:是什麼讓一個真實的作業系統「真實」——當你把兩套擺在一起比較時,你到底在比什麼?三個問題就能理清大半。第一,它的血統:它從哪個家族傳下來、又繼承了什麼樣的設計品味。第二,它的核心結構:那個核心是一支大而緊密相連的程式、一個極小的最小核心、還是兩者的混血?第三,它的目標硬體:它是為手機、筆電、伺服器、還是一台沒有螢幕的小型嵌入式控制器而打造的?幾乎其他一切——外觀、工具、名稱——都從這三個選擇順流而下。
Unix 與它的哲學
你會遇到的幾乎每一套現代系統,都直接、或藉著模仿,回溯到 Unix——一套 1970 年代初在貝爾實驗室寫成的作業系統。讓 Unix 重要的,不是某個單一功能,而是一套關於「軟體該怎麼造」的、彼此連貫的品味,如今被記成Unix 哲學。那些口號好記、卻出奇地深:寫只把一件事做好的程式;寫能彼此協作的程式;並把文字串流當成它們之間的共通語言,因為文字是每個工具都早已會說的通用介面。
那套品味最有名的表現,是「一切皆檔案」這個想法。在 Unix 裡,你不用為磁碟學一種特殊介面、為鍵盤學另一種、為網路再學一種、為一個運作中的裝置又學一種。相反地,幾乎全部都以檔案的樣貌呈現:你用同一小撮操作去開啟、讀取、寫入的東西。你的終端機是一個檔案。一條網路連線看起來像一個檔案。連核心資訊都被曝露成你可以直接讀的檔案。正是那一個統一的決定,讓一支只懂得讀寫文字的小工具,能在不自知的情況下,處理來自磁碟、感測器、或地球另一端的資料。
這也正是前幾階那些抽象概念不再抽象的地方。你透過那個統一介面開啟的「檔案」,恰恰就是你研讀過的檔案系統抽象;那些小而可組合的工具,不過是核心在排程的行程;那條讓一個工具餵給另一個工具的管線,則是核心悄悄地把兩個行程接在一起。與其說 Unix 發明了這些機制,不如說它把它們安排成一套哲學——一個強硬的主張:由統一介面組合起來的、簡單而銳利的工具,勝過任何一支想把所有事都做完的巨型程式。
Linux 核心
如果說 Unix 是那套哲學,那麼 Linux 核心 就是它最成功的、還活著的後裔。Linux 並不是原本的 Unix——它是 1991 年起從頭寫起的——但它從骨子裡就是「類 Unix」,忠於那套哲學、也忠於「一切皆檔案」的介面。讓它與眾不同的,是它被打造的方式:公開地、由全世界數以千計的貢獻者一起打造,原始碼免費供任何人閱讀、修改、出貨。正是那套開放的開發模式,而不是任何單一的技術巧招,讓 Linux 散佈到幾乎每一種電腦上。
在引擎蓋下,Linux 做了一個你早先見過的、具體的核心結構選擇:它是一個單核心。那意思是說,那些大型的子系統——排程器、記憶體管理器、檔案系統、網路堆疊、裝置驅動程式——全都住在同一支程式裡,在單一的共用位址空間中、以核心模式運行。相反的設計,微核心,則把核心保持得極小,並把那些服務推到外面、成為獨立的程式。單核心快,因為子系統彼此直接呼叫、不必跨越保護邊界;其代價是一個有臭蟲的驅動程式,跟其他一切住在同一塊空間裡,原則上能把整個核心拖垮。
但 Linux 是單核心而且模組化的,那個「而且」正是巧妙之處。透過可載入核心模組,一塊塊核心程式碼——最常見的是裝置驅動程式與檔案系統——可以在不重新建構、也不重開機的情況下,被載入運行中的核心、再卸載掉。於是你同時得到一個緊密整合的核心的速度,以及微核心當初想追求的那種彈性的一大部分:核心出貨時很小,只長出某台機器真正需要的那些部分。插上一個陌生的裝置,相對應的模組就會按需載入;那就是「單核心但模組化」正在運作的樣子。
你學過的每個概念都在哪裡現身
現在,把 Linux 當成一個具體的例子,重讀那些抽象的階段,整道階梯就會驟然對焦。你研讀過的排程器,是一塊真實的程式碼,在每個核心上挑選下一個要跑的執行緒。虛擬記憶體,是硬體在每次存取時都會走過的、活生生的分頁表。檔案系統,是磁碟上的佈局、外加那個把「開啟這條路徑」變成區塊讀取的核心層。中斷與驅動程式,是核心跟真實裝置對話的方式。在一個運行中的 Linux 核心 內部,你爬過的每一章都同時在場、彼此協作——而你現在已經有了字彙,能去讀它的原始碼、認出那些老朋友。
這也是個好時機,回想一下核心在這台機器裡的位置。核心是那個在特權模式下運行、並仲裁每個程式對硬體之存取的唯一程式;其他一切——你的 shell、你的瀏覽器、你的編輯器——都是普通的行程,透過系統呼叫向核心要東西。要把一套真實作業系統理清楚,有個實用的辦法是子系統視角:把核心想像成幾個彼此合作的部門——行程與排程、記憶體、檔案系統與儲存、網路、以及裝置驅動程式——每個部門各自掌管你學過的一個概念。一個部門一個部門地去比較兩套作業系統,差異就會變得容易看清得多。
搭好比較的舞台
有了 Unix 與 Linux 當我們的錨,這一階其餘部分的比較框架就到位了。當你在接下來的導覽裡遇到另一套真實作業系統時,拿同樣的三個問題、外加一個把它們串起來的第四個問題——它的核心結構選擇——來檢視它。
- 血統:它從哪裡傳下來?類 Unix(Linux、macOS、Android)繼承了那套哲學、以及「一切皆檔案」的本能;Windows NT 則從一個另外的傳統長出來,帶著不同的品味。
- 核心結構:那個核心是單核心(Linux)、微核心、還是模組化的混血?這是塑造核心速度、安全、以及它如何成長的那一個選擇。
- 目標硬體:手機、筆電、伺服器、還是一台小小的控制器?跑在微控制器上的嵌入式作業系統、以及煞車控制器裡的即時作業系統,所做的取捨跟桌機非常不同。
- 然後把它的子系統對應回你學過的那些概念:找出它的排程器、它的虛擬記憶體、它的檔案系統、它的驅動程式模型。名稱不一樣;但那些工作,正是你已經理解的那些。
把那個框架握好。在下一篇導覽裡,它會真正派上用場:Windows NT、macOS 與 iOS 底下的 XNU 混合核心、坐在 Linux 核心之上的 Android、以及即時與嵌入式的世界,各自以不同的方式回答那四個問題,而那正是它們值得拿來比較、而不是死記的原因。