banner
MIG

MIG

Angelos·MIG·Trubetskoy

Mac OS X 背後的故事 叁

Mach 之父 Avie Tevanian#

文 / 王越

1975 年,美國羅徹斯特大學紐約分校,一組研究員正在做一個名為 RIG(Rochester’s Intelligent Gateway)的項目,它由 Jerry Feldman 主持設計。RIG 的目標是給所有本地以及遠端的計算設備(比如磁碟、列印機、磁帶、繪圖機等)提供一組統一的訪問方式,其作業系統稱為 Aleph。

Jerry Feldman.jpg
Jerry Feldman

為了實現所需要的功能,Aleph 的內核主要構建了一個進程交互(Interprocess Communication,IPC)的機制。RIG 的各進程,只要設置了目標端口,就可以彼此間發送信息。RIG 項目沒過幾年就被判了死刑,主要是缺少很多有用的功能,比如端口沒有保護機制,一次最多只能發送 2KB 大小的信息(受硬件限制),也沒有很好的網絡支持等。不過在 20 世紀 70 年代,這個系統依然代表著當時作業系統設計的先進水平,比如除了進程交互外,每個進程還有內存保護的功能,這足以讓 20 世紀 90 年代末都沒有做出內存保護技術的 Apple 公司汗顏。

Rochester’s Intelligent Gateway.jpg
當時對此系統的報導

該項目後來失敗了,隨後在 1979 年,RIG 的 Richard Rashid 博士畢業到卡內基 - 梅隆大學當教授,開始做 Accent 項目。它是一個網絡作業系統,於 1981 年 4 月開始活躍開發。受 RIG 的影響,Accent 系統的亮點也在於可以使用 IPC,而且解決了很多 RIG 的不足。比如每個進程有 4GB 的虛擬內存空間,而且甚至連內核自己都可以被存入快取頁面,內存有先進的更新前拷貝(Copy-on-Write)功能,可以實現進程間大信息的傳送等。讀者可以把 Accent 理解為支持虛擬內存技術,並且具有網絡透明 IPC 功能的 RIG 內核。

Richard Rashid.jpg
Richard Rashid

但過了幾年,開發者們越來越對 Accent 失去興趣。在 1980 年初,很多人覺得多核計算是計算機未來發展的潮流,但 Accent 內核在設計時並沒有考慮到這些問題。而且,隨著許多實驗室紛紛購置性能更強勁的計算機,這就意味著 Accent 需要移植到新的目標架構上。此外,Unix 正大行其道,不管是在作業系統理論上還是在用戶程序上,都成為最為流行的作業系統模式,而 Accent 並不是一個 Unix 系統,所以無法享受 Unix 世界的諸多美好。為了解決這個問題,研究人員決定把所有設計推翻重來,於是就有了一個全新的系統。

在匹茲堡的一個雨天,卡內基 - 梅隆大學的 Avie Tevanian,此系統的最主要開發者,正打著傘和同學們在去吃午飯的路上。他們一邊繞著無數的泥塘,一邊構思給這個新系統取什麼名字好。靈感突來,Avadis Tevanian 建議把這個系統叫作 Muck,引得同學們哈哈大笑。後來,Richard Rashid 和一位意大利同事 Dario Giuse 說起這玩笑,結果這位同事不經意地把 Muck 發為 Mach,遂把 Richard Rashid 笑翻,偉大的 Mach 系統因此得名。

Avie Tevanian2.jpg
Avie Tevanian

Mach 是一個受 Accent 啟發而搞出的 Unix 兼容系統。那年,Unix 已經十六歲,而且依然是作業系統理論與實踐開發的主要陣地。Unix 內核由於新加入的功能越來越多,變得越來越複雜。而 Mach 的一個主要目標就是儘量縮減 Unix 的各項服務,以使內核變得簡單可維護。此項目從 1984 年開始,目標主要是包含完整的多任務支援、良好的硬件移植性,並要把大量服務移出內核作為跑在內核上的服務,以及提供與 Unix 的兼容性。

Mach 使用純 C 編寫,所以在一定程度上保證了可移植性,這實際上為後面的 NeXT 向 PowerPC 移植以及 2005 年的向 Intel 移植提供了很重要的前提。而為了縮減內核該管的任務,Mach 做得很絕,只提供內存和處理器管理。類似於檔案系統、網絡、輸入輸出等功能都作為單個的系統進程,獨立執行於內核之上。

Mach 對多處理器的支持.png
Mach 對多處理器的支持

Mach 的開發過程以 4.3BSD 作為起點,以 RIG 的 Accent 作為參考,採納 DEC 的虛擬內存設計思路,逐步開發,以新寫的代碼代替 BSD 的代碼。兩年後的 1986 年,雖然沒能把系統服務完全分離於內核之外,但已頗見成效。Mach 第一版大功告成,組員發表會議論文,成為操作系統史上里程碑式的經典,引發操作系統業界的「微內核」學潮,如今學習作業系統設計的皆需學習此文,二十五年來被引用一千二百餘次。

文章.png
該論文

這篇文章主要講了兩方面內容:IPC 和虛擬內存。在 IPC 方面,Mach 把複雜的消息傳送機制分為四個獨立的清晰概念:任務、線程、端口、信息。任務是擁有一組系統資源的對象,允許線程在其中執行;線程是執行的基本單位,擁有一個任務的上下文,並且共享任務中的資源。由於該論文的影響力,所以項目得到了 OSF(Open Software Foundation)在內的很多投資。

Mach.jpg
Mach 的幾個基本抽象

當然了,學術和工程永遠存在差距,所以即使是最受歡迎的 Mach 2.5 其實仍然是一個包括大多數 BSD 服務層的單內核。但包括 NeXTSTEP、OSF/1 在內的很多操作系統都採用 Mach 作為其內核技術,原因是廣大研究人員依然相信微內核代表著未來。

雖然 Mach 2.5 的效率比傳統的 Unix 系統稍低一些,但研究者們表示情緒淡定,因為 Mach 支持多處理器系統,可以利用多線程把任務處理得飛快,相比之下其他 Unix 內核並沒有多處理器的完善支援,因此 Mach 效率稍低完全可以接受。但隨著真正把 Mach 和 BSD 服務完全脫離的 Mach 3 微內核面世,研究人員們的情緒就再也淡定不下來了。因為服務和內核分離後,任務間的 IPC 數量暴漲,一個簡單的 Unix 系統調用要涉及到十多個開端口、設權限、發送、收取消息的操作,哪怕是使用數年後的 1997 年的硬件,跑一個系統調用密集的程序,Mach 的效率要比一般的 Unix 系統慢 50%,而且根本沒有什麼好方法來解決這個問題。
所以 Mach 3 出來後,雖有少數微內核信徒繼續執著地改進 Mach,或者開始其他微內核比如 L4 的研究。但學術界對 Mach 的興趣大減,因而 Mach 3 也成為最後一版。項目解散後,Richard Rashid 去了微軟研究院。

再說我們的主角 Avie Tevanian,他 1987 年博士畢業去了 NeXT。這家公司剛剛由 Steve Jobs 成立兩年,這兩年 Steve Jobs 啥正經事都沒幹,只是花了十萬美元雇 Paul Rand 設計了一個公司商標。直到 Avie Tevanian 加入後,這個公司才開始幹實事。1987 年公司確認要開發一個面向研究人員使用的計算機工作站,於是軟硬件的開發工作緊鑼密鼓地展開。硬件組由領導過 Apple Lisa 的 Rich Page 原班人馬負責,而軟件則由 Avie Tevanian 負責,計劃開發一個有圖形界面的操作系統 NeXTSTEP。由於 Avie Tevanian 是 Mach 主要的開發者,自然 NeXTSTEP 就基於 Mach 了。1988 年 10 月 12 日,NeXT 發布預覽版(0.8 版),並於 1989 年 9 月 18 日發布 1.0 版

NeXTSTEP 系統.jpg
NeXTSTEP 系統

作為 NeXTSTEP 系統的內核,NeXT 分支的 Mach 經歷了不少變化。NeXTSTEP 0.8 主要使用 Mach 2.0 版,而稍後的 NeXTSTEP 1.0 版主要基於 Mach 2.5 版,包含一個自己定制的當時最新的 4.3BSD 服務層。

從 3.1 版開始,NeXT 分支的 Mach 還包括一個全新的設備驅動框架,名為 DriverKit,僅供 x86 系列的硬件使用。和 Mach 以及 BSD 代碼不同,Driver Kit 是使用 Objective-C 寫的。為什麼是個面向對象的語言呢?看 NeXTSTEP 3.3 的 DriverKit 文檔。讀者大概就會發現,NeXTSTEP 把所有硬件設備理解為對象,而我們知道,對象之間有繼承關係,比如,磁碟(IODisk 物件)屬於輸入輸出設備(IODevice 物件)的子物件,而磁碟(IODisk)本身又是邏輯磁碟(IOLogicalDisk)的父物件。硬件的初始化對應於每個物件的初始化(init 方法),硬件又有讀、寫,所以可以用 getter/setter 的方法。因此,DriverKit 是一個非常有特色的實現。而且由於 Objective-C 的效率很高,依賴很少(Objective-C 程序可以直接被編譯器翻譯成等價的 C 語言程序並編譯,而 Objective-C 的運行庫 libobjc 也以高效著稱),所以也是編寫驅動的良好選擇。幾年後的 IOKit 其實就是個 DriverKit 的翻版。

這時,NeXTSTEP 操作系統大獲成功,風險投資商們紛紛購買,但硬件卻始終賣不出去1,所以 NeXT 砍掉了硬件部門專做軟件,更是使 NeXTSTEP 發展到了巔峰時期,同時支持 68K、x86、PA-RISC 和 SPARC 等硬件,但頗有意味的是它就是不支持 PowerPC 架構。它可以同時產生一個包含所有架構可執行碼的二進制文件,來使開發的程序在所有平台上執行。這個功能也影響了後來 Mac OS X 的技術。Mac OS X 10.4 時代有兩件跨時代意義的事情,一件是 Apple 搞出了 64 位的 Power Mac,開發者可以發布一個包含 64 位和 32 位程序的單一可執行文件,而無需讓用戶去區分;另一件是和 Intel 合作。Apple 正式發表了 Universal Binary 技術,可以一個 Mach-O 文件同時包含 Intel 和 PowerPC 的指令。這非常貼心的設計(要知道,大多數電腦用戶根本不知道 Intel、PowerPC、64 位、32 位等技術)就是來自於 Mach 的技術。

Mac OS X 架構圖.jpg
Mac OS X 架構圖

NeXTSTEP 3.3 後,NeXTSTEP 因為 NeXT 和 Sun 的合作改名為 OPENSTEP,1996 年發布 4.0 版,到 1997 年 2 月 4 日,NeXT 被 Apple 收購之前,期間內核改進除源碼同步到 Mach 3.0 版外不明,而且出於不知道的原因,我手頭的 OPENSTEP 正式版光碟中,居然找不到 DriverKit 的發布說明和編程文檔,故不作詳述。不過這段時間,Apple 的活動值得好好一說。之前在《Linus Torvalds 的短視》中,我們曾提到,1996 年,Apple 和 OSF 曾經合作,把 Mach 移到 PowerPC Mac 上,再把 Linux 作為單一的服務跑在 Mach 上,這個項目叫做 MkLinux。在 1996 年發布基於 Mach 3.0 和 Linux 1.3 的預覽版,並更新到 2002 年結束其歷史使命,對 Mach 在 PowerPC 的移植性上做出了重要貢獻。這個 PowerPC 版的 Mach 被叫作 osfmk 分支,也正是現在 Mac OS X 中用的分支。當然了,NeXT 被合併後做了大量修改。

mklinux.jpg
Mklinux 系統

Apple 收購 NeXT 後,Mach 被確定作為未來的操作系統核心。Avie Tevanian 被選為軟件開發部的總裁。合併所有項目的號角吹響後,上層的 OpenStep API 和老版 Mac OS 的部件開始合併,而 Mach 也經歷重大變化。主要是一方面,Mach 使用了 osfmk 分支,但依然包含 4.3BSD 服務;另一方面,DriverKit 被 IOKit 取代。這是 Apple 走得很被動的一步。因為當時外界普遍對 Objective-C 不看好,逼著 Apple 走老版 Mac OS API 的老路。而 Apple 自己對 Objective-C 也很不自信,甚至想索性換用 Java 了事(我們以後會談及這段不自信的歷史)。所以 IOKit 是一個 C 的驅動架構,來符合大眾口味。這些改變最早在 Rhapsody 中出現(我們以後也會有一期 Rhapsody 的專題)。但由於 C 是門很恐怖的語言,所以 Apple 又把 C 給阉割了,去掉了多重繼承、模板、運行時動態以及異常,讓開發者使用這種對於 Objective-C 來說換湯不換藥的 Clean C 來做驅動。但公正地說,IOKit 對於 Driver Kit 是有不少改進的,比如 IOKit 可以寫在用戶空間跑的驅動(雖然大多仍是跑在內核空間上的),因而驅動掛了而系統不會掛。另外 IOKit 考慮到了計算機發展的趨勢,所以在電源管理、即插即用、動態加載上做得更好。

但各位也知道,C 程序得用專門的運行庫才能跑,所以 Mach 中又加入了一個叫作 libkern 的庫負責 C 相關的功能,同時,還有一個 libsa 的庫提供一些類似二分查找、排序等基本算法之類的功能。最後和硬件相關的還有一個叫作 pexpert(Platform Expert)的庫,負責收集硬件設備列表、檢測機器種類(比如處理器速度等)、解析啟動參數等雜活。

至此,Mac OS X 的內核完全形成,形成 BSD、IOKit、Mach osfmk 三足鼎立的態勢,並有 pexpert、libkern、libsa 作為基礎。Apple 稱它的內核傑作為 XNU。其代碼開源 2。由於 4.3BSD 已是過眼煙雲,Apple 後來投入大量資源扶持 FreeBSD 開發。2001 年,Apple 將 FreeBSD 的發起者、領軍人物 Jordan Hubbard 收入麾下,並在 Mac OS X 10.3 時基本同步到 FreeBSD 5 的代碼

XNU 內核演變.jpg
XNU 內核演變

另外,Apple 的開發也同時反饋到 FreeBSD 小組,包括 FreeBSD 6.2 內核引入的 AUDIT(man audit)3 ,後來 FreeBSD 8 引入的 libdispatch,(在 Apple 這項技術叫 Grand Central Dispatch,是 Mac OS X 10.6 主推的新功能,FreeBSD 基本在 Mac OS X 10.6 上市的同時就擁有這項最新技術),以及 FreeBSD-CURRENT 中的 LLVM-Clang,全是 Apple 的手筆。從 1999 年開始,FreeBSD 源碼倉庫可以搜索到 Apple 提供的大量的補丁以及新功能。

Mac OS X 早期版本不太穩定,所以會內核崩潰。10.0 版本會直接像 Linux 或者 BSD 那樣打出回溯信息,很不美觀,所以 Apple 在 10.2 版本開始設計了一個多國語言的圖片告訴用戶你的內核崩潰了,以讓內核崩得看起來更優雅一點。由於包含四國語言,被國內用戶戲稱為「四國」,這是 XNU 的 Mach osfmk 部分的功能。但從 10.3-10.4 版本開始,系統越發穩定,正常使用已很少見到內核崩潰。而且,內核提供的服務也越來越多,使得 Mac OS X 成為一個完善的系統。

四國語言.jpg
著名的「四國語言」,現今已是六國

21 世紀 XNU 架構方面的最重大改動是支持了 PPC64(10.4 版本時代)、x86 架構(其實本來也一直支持的,以後講 Apple 的 Intel 遷移時詳談)、x86_64(64 位支持是蘋果長年努力逐步展開的。10.4 時代 32 位內核支持載入 64 位的用戶程序,10.5 系統提供 64 位的 Cocoa 框架,但系統大部分程序都是 32 位的,10.6 時代內核支持以 64 位模式啟動,但在不少硬件上這是非默認的方式,但系統大量程序已被改寫並編譯為 64 位的二進制程序,10.7 時代內核默認以 64 位模式啟動。)和 ARM 架構(iPhone 和 iPad 使用 XNU 內核)等多個新架構。而其中 ARM 架構的支持別具意義。但 2006 年 5 月 31 日,功成名就的 Avie Tevanian 離開 Apple 另謀發展,此時,離 Apple 的 iPhone 奇蹟發生,只有不到一年時間。

本文作者王越,美國賓夕法尼亞大學計算機系研究生,中國著名 TeX 開發者,非著名 OpenFOAM 開發者。

王越老師是我最崇敬的人之一,此系列文章發布至今已有十余年,網絡上已幾無完整版本,在下希望能在此基礎上進一步完善,讓更多人所知。

參考資料:

Footnotes#

  1. 參見 Aaron Hillegass《Cocoa Programming for Mac OS X》前言

  2. 請讀者移步https://opensource.apple.com/source/xnu/xnu-123.5/ 每個部分的代碼都獨立存放在一個文件夾中,條理清晰,不妨一讀。

  3. 參見 https://www.freebsd.org/releases/6.2R/announce/

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。