vlambda博客
学习文章列表

Mac OS X 背后的故事(三):Mach 之父 Avie Tevanian

来源 | 《程序员》杂志
作者 | 王越,美国宾夕法尼亚大学计算机系研究生,中国著名 TeX 开发者,非著名 OpenFOAM 开发者。

这是很老文章,全文共 9 个部分 13 篇,一起来看看那段历史,感受一下 Mac OS X 背后的故事

1975 年,美国罗彻斯特大学纽约分校,一组研究员正在做一个名为 RIG(Rochester’s Intelligent Gateway)的项目,它由 Jerry Feldman 主持设计。RIG 的目标是给所有本地以及远端的计算设备(比如磁盘、列印机、磁带、绘图机等)提供一组统一的访问方式,其作业系统称为 Aleph。为了实现所需要的功能,Aleph 的内核主要构建了一个进程交互(Interprocess Communication,IPC)的机制。RIG 的各进程,只要设置了目标端口,就可以彼此间发送信息。RIG 项目没过几年就被判了死刑,主要是缺少很多有用的功能,比如端口没有保护机制,一次最多只能发送 2KB 大小的信息(受硬件限制),也没有很好的网络支持等。不过在 20 世纪 70 年代,这个系统依然代表着当时作业系统设计的先进水平,比如除了进程交互外,每个进程还有内存保护的功能,这足以让 20 世纪 90 年代末都没有做出内存保护技术的 Apple 公司汗颜。

Mac OS X 背后的故事(三):Mach 之父 Avie Tevanian

该项目后来失败了,随后在 1979 年,RIG 的 Richard Rashid 博士毕业到卡内基-梅隆大学当教授,开始做 Accent 项目。它是一个网络作业系统,于 1981 年 4 月开始活跃开发。受 RIG 的影响,Accent 系统的亮点也在于可以使用 IPC,而且解决了很多 RIG 的不足。比如每个进程有 4GB 的虚拟内存空间,而且甚至连内核自已都可以被存入缓存页面,内存有先进的更新前拷贝(Copy-on-Write)功能,可以实现进程间大信息的传送等。读者可以把 Accent 理解为支持虚拟内存技术,并且具有网络透明 IPC 功能的 RIG 内核。

但过了几年,开发者们越来越对 Accent 失去兴趣。在 1980 年初,很多人觉得多核计算是计算机未来发展的潮流,但 Accent 内核在设计时并没有考虑到这些问题。而且,随着许多实验室纷纷购置性能更强劲的计算机,这就意味着 Accent 需要移植到新的目标架构上。此外,Unix 正大行其道,不管是在作业系统理论上还是在用户程序上,都成为最为流行的作业系统模式,而 Accent 并不是一个 Unix 系统,所以无法享受 Unix 世界的诸多美好。为了解决这个问题,研究人员决定把所有设计推翻重来,于是就有了一个全新的系统。

在匹兹堡的一个雨天,卡内基-梅隆大学的 Avie Tevanian,此系统的最主要开发者,正打着伞和同学们在去吃午饭的路上。他们一边绕着无数的泥塘,一边构思给这个新系统取什么名字好。灵感突来, Avadis Tevanian 建议把这个系统叫作 Muck,引得同学们哈哈大笑。后来,Richard Rashid 和一位意大利同事 Dario Giuse 说起这玩笑,结果这位同事不经意地把 Muck 发为 Mach,遂把 Richard Rashid 笑翻,伟大的 Mach 系统因此得名。

Mach 是一个受 Accent 启发而搞出的Unix兼容系统。那年,Unix 已经十六岁,而且依然是作业系统理论与实践开发的主要阵地。Unix 内核由于新加入的功能越来越多,变得越来越复杂。而 Mach 的一个主要目标就是尽量缩减 Unix 的各项服务,以使内核变得简单可维护。此项目从 1984 年开始,目标主要是包含完整的多任务支援、良好的硬件移植性,并要把大量服务移出内核作为跑在内核上的服务,以及提供与 Unix 的兼容性。

Mach 使用纯 C 编写,所以在一定程度上保证了可移植性,这事实上为后面的 NeXT 向 PowerPC 移植以及 2005 年的向 Intel 移植提供了很重要的前提。而为了缩减内核该管的任务,Mach 做得很绝,只提供内存和处理器管理。类似于档案系统、网络、输入输出等功能都作为单个的系统进程,独立执行于内核之上。Mach 的开发过程以 4.3 BSD 作为起点,以 RIG 的 Accent 作为参考,采纳 DEC 的虚拟内存设计思路,逐步开发,以新写的代码代替 BSD 的代码。两年后的 1986 年,虽然没能把系统服务完全分离于内核之外,但已颇见成效。Mach 第一版大功告成,组员发表会议论文,成为操作系统史上里程碑式的经典,引发操作系统业界的“微内核”学潮,如今学习作业系统设计的皆需学习此文,二十五年来被引用一千二百余次。

这篇文章主要讲了两方面内容:IPC 和虚拟内存。在 IPC 方面,Mach 把复杂的消息传送机制分为四个独立的清晰概念—任务、线程、端口、信息。任务是拥有一组系统资源的对象,允许线程在其中执行;线程是执行的基本单位,拥有一个任务的上下文,并且共享任务中的资源。

由于该论文的影响力,所以项目得到了 OSF(Open Software Foundation)在内的很多投资。当然了,学术和工程永远存在差距,所以即使是最受欢迎的 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 版(注:http://en.wikipedia.org/wiki/NeXTSTEP)。

作为 NeXTSTEP 系统的内核,NeXT 分支的 Mach 经历了不少变化。NeXTSTEP 0.8 主要使用 Mach 2.0 版,而稍后的 NeXTSTEP 1.0 版主要基于 Mach 2.5 版,包含一个自己定制的当时最新的 4.3 BSD 服务层。从 3.1 版开始,NeXT 分支的 Mach 还包括一个全新的设备驱动框架, 名为 Driver Kit,仅供 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 操作系统大获成功,风险投资商们纷纷购买,但硬件却始终卖不出去(注:Aaron Hillegass《Cocoa Programming for Mac OS X》前言),所以 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 的技术。

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 被合并后做了大量修改。

Apple 收购 NeXT 后,Mach 被确定作为未来的操作系统核心。Avie Tevanian 被选为软件开发部的总裁。合并所有项目的号角吹响后,上层的 OpenStep API 和老版 Mac OS 的部件开始合并,而 Mach 也经历重大变化。主要是一方面,Mach 使用了 osfmk 分支,但依然包含 4.3 BSD 服务;另一方面,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。其代码开源,请读者移步http://www.opensource.apple.com/source/xnu/xnu-123.5/,每个部分的代码都独立存放在一个文件夹中,条理清晰,不妨一读。

由于 4.3 BSD 已是过眼烟云,Apple 后来投入大量资源扶持 FreeBSD 开发。2001 年,Apple 将 FreeBSD 的发起者、领军人物 Jordan Hubbard 收入麾下,并在 Mac OS X 10.3 时基本同步到 FreeBSD 5 的代码(注:http://osxbook.com/book/bonus/ancient/whatismacosx/arch_xnu.html)。

另外,Apple 的开发也同时反馈到 FreeBSD 小组,包括 FreeBSD 6.2 内核引入的 AUDIT (man audit 或参见http://manpages.unixforum.co.uk/man-pages/unix/freebsd-6.2/4/audit-man-page.html),后来 FreeBSD 8引入的 libdispatch (http://wiki.freebsd.org/GCD, 在 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 版本开始设计了一个多国语言的图片告诉用户你的内核崩溃了,以让内核崩得看起来更优雅一点。由于包含四国语言,被国内用户戏称为“四国”(注:优雅的图片见下图,详见 http://support.apple.com/kb/ht1392),这是 XNU 的 Mach osfmk 部分的功能。但从 10.3~10.4 版本开始,系统越发稳定,正常使用已很少见到内核崩溃。而且,内核提供的服务也越来越多,使得 Mac OS X 成为一个完善的系统。

Mac OS X 背后的故事(三):Mach 之父 Avie Tevanian

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 奇迹发生,只有不到一年时间。

前章


后续

(四)政客的跨界
(五)Jean – Marie Hullot 的 Interface Builder 神话
(六)上善若水 —— Cordell Ratzlaff 引发的 Aqua 革命(上、下)
(七)三好学生 Chris Lattner 的 LLVM 编译工具链
(八)半导体的丰收(上、中、下)
(九)Mac OS X 文件系统的来龙去脉(上、下)

推荐阅读

在看就点点吧