64 位支持是 Mac OS X Snow Leopard 操作系统最重要的新特性之一。这往往让人以为 Apple 是初次提供 64 位支持。其实 OS X 的 64 位支持从 Tiger 开始就默默存在了。Apple 一贯的风格是做得多说的少 —— 能把 x86 架构的 OS X 研发保密达 5 年之久,它最喜欢在发布会上宣布的消息是『available now』。
64 位支持并非从 Tiger 开始就一步到位。否则的话,Leopard 和 Snow Leopard 有固步不前之嫌,Apple 对 64 位支持保持 4 年的市场宣传沉默也显得毫无必要。下面这幅图说明了 OS X 系统 64 位支持的发展路径。Tiger 仅仅支持没有 GUI 的 64 位应用,Leopard 仅仅在 user space 提供 Cocoa 的 64 位支持,没有 64 位 kernel。而且这两者都仅仅提供系统级的支持,附带的应用仍然都是 32 位。Snow Leopard 的 64 位达到成熟,附带的应用几乎全部为 64 位,并且提供 64 位 kernel(尽管不是缺省设置)。

有意思的是,OS X 系统在 64 位上循序渐进的发展策略,正好有意无意的遵循了 UNIX 的设计文化关于 GUI 的设计的原则。《The Art of UNIX Programming》在第 11.6 章讨论 UI 设计之前就开宗明义地宣布『UNIX 没有发展出本土的 GUI 设计模式』。确实,UNIX 在这点上保持谦逊,向 MacOS(这里指classic)、NeXTStep和其它 GUI 的先行者借鉴了许多经验(以及后来的 OS X 与 UNIX 的相互借鉴)。不过随后在第 11.6.8 节指出了 UNIX 在 GUI 方面还是发展出了一个最基本的准则 —— 『界面和引擎的分离』。UNIX 提倡把尽可能多的代码放到没有可见 GUI 的进程中(即引擎进程),提供 GUI 的进程和引擎进程通过 Application Protocol 通信。引擎进程一般不与用户直接交互,但是很多引擎程序也提供让高级用户直接调用的接口(比如 CLI 命令)。这样做既符合 UNIX 通过协作的多个进程来降低整体复杂度的原则,还让程序能够同时满足初级用户和高级用户的不同使用习惯。甚至程序本身的自动化测试也更为方便。现实中很多程序都在实践这一原则,比如我们每天都用的 P4V,它本身的 GUI 并不实现和 Perforce server 的通信,而是调用 Perforce 的命令行客户端程序。这样即满足了初级用户,也让高级用户了解 GUI 操作对应的都是哪些命令,方便了 trouble shooting 和重复操作的自动化。设计良好的引擎进程还允许第三方开发更好的或者满足特殊用户需求的 GUI。
如果一个系统无法在一个 release 中实现完全的 64 位支持,那么应该如何决定模块 64 位化的先后顺序呢?以上面的 UNIX 原则为依据来决定的话,就正好是 OS X 系统对 64 位支持的实现顺序(尽管也许是无意的,但是我相信 Apple 内部的 UNIX 大牛们有此特意的考虑)。首先提供对 GUI-less 进程的 64 位支持。这样在界面引擎分离的系统中,引擎部分可以首先 64 位化。其实 64 位化带来的性能和可扩展性(scalability)的改进对于界面进程并没有太大影响,而急需此类提升的引擎进程正好可以先一步利用系统的优势。
到了今天的全 64 位 Snow Leopard 系统,除了安全和整体复杂度的考虑,界面引擎分离的原则是否在 32/64 位架构方面还有作用?仍然有。比如,Dropbox 是一个保证文件在多台机器上同步的程序。它由一个提供同步功能的进程和一个 Finder plug-in 构成。Finder 由 Cocoa 重写并且升级为 64 位之后,plug-in 停止工作,所以无法使用 Finder 右键菜单中的 Dropbox 功能,但是提供同步功能的进程仍然可以工作。Dropbox 的引擎界面分离让失败降低到最小的程度。Safari 升级到 64 位之后,很多第三方的 plug-in 仍然没有来得及跟进。但是这些 plug-in 的重要性让 Apple 没有办法说服用户以抛弃它们为代价享用 64 位。所以 Safari 采取了一种特殊的界面引擎分离。把 32 位的 plug-in 放置在单独的、32 位的虚拟 Safari hosting 环境的进程中运行。这些 32 位虚拟 Safari hosting 进程和 64 位的 Safari 通过 application protocol 通信 —— 称之为 out-of-process plug-in。即便如 Flash 视频这样的应用,以今天的硬件性能来通过 IPC 在两个进程间传输数据也无损用户体验。这样做在满足了 32/64 位架构兼容的同时也提供了进程协作的一贯好处 —— 安全、稳定(单个 plug-in 崩溃不会影响整个浏览器)和易于维护(容易定位 bug)。即便今后有 64 位 plug-in 出现,这些好处仍然会促使 Safari 和其它应用采用 out-of-process plug-in 技术。
Snow Leopard 引入 64 位 kernel 也让另一个利用普通进程技术的优势体现出来。TOR(洋葱路由)基于 SOCKS Proxy 技术,所以它的 client 端实现是一个监听特定端口(一般是 9050)并提供 SOCKS 服务的普通进程。Cisco VPN 基于虚拟以太网技术,所以它的 client 端实现是一个虚拟的网卡驱动,运行在 kernel space。当 kernel 升级为 64 位而 Cisco VPN client 无法跟进的时候,用户只好放弃使用其一 —— 退回 32 位 kernel 或者不使用 VPN。而基于普通进程的 TOR 则不受影响。同样,基于普通进程的 SSH tunnel 技术也不受 kernel 64 位升级的影响。同样是提供加密的传输功能,基于普通进程的技术显示了灵活性。
计算机系统各个部分的发展永远呈现不同步的状态。OS X 的 64 位化过程清晰而富有趣味性的重申了这一点。软件应对这一永恒趋势的唯一手段就是把自己分割成一个个功能简单,可以独立替换,甚至在某些其它模块缺失的时候仍然可以正常工作的模块。这是 UNIX 的基本设计原则之一,利用 application protocol 进行协作的进程就是 UNIX 实践这个原则的工程传统。那些在 Tiger 上就利用了 GUI-less 64 位支持的程序、那些在 Leopard 上来不及把 GUI 升级为 Cocoa 的程序、还有 Snow Leopard 上的各种成功和失败的例子都在重申这一原则的重要性。UNIX 诞生于资源奇缺的计算环境。因此演化出『沉默是金』这样的传统(尽管今日沉默是金是因为有了其它的优势而被遵守)。但是同时也顽强的保留了多进程协作这样看似『奢侈』的传统。不能不惊叹于 UNIX 文化的预见性和适应性。