[UNIX分时系统程序员手册]

euc注:
    UNIX手册由UNIX的创造者及核心开发者所写,手册上册陈述了UNIX某个老版本的所有指令;下册由38篇论文组成,都是UNIX的先驱者们的杰作,极具学习、收藏价值和历史意义。本文只摘抄了中文版(198x年)下册的少部分显示其历史背景的、有设计思想的段落。原本还有两篇关于C语言编译程序原理的论文—《D.M.Ritchie, UNIX系统C语言编译程序介绍》和《S.C.Johnson, 可移植的C语言编译程序综述》。由于水平所限,俺只能看懂一点,所以这里只抄一点。

D.M.Ritchie K.Thompson, UNIX分时系统

    UNIX的最重要的成就也许是表明一个强有力的交互使用操作系统不需要在设备上花高价,也不必在人力上花高价。它能够在仅需花费四万美元的硬件上运行,在主要的系统软件上耗费小于两个人年。不过我们希望用户将发现该系统最重要的特征是系统简单、雅致和易于使用。
...
    Research UNIX系统安装在PDP-11/70上,这是一台字长16位、内存768K字节的计算机,系统内核占用90K字节,其中代码和数据表格各占一半。不过,这个系统还包括大量的各种设备驱动程序以及一个足够分配的输入/输出缓冲和系统表格空间。可以运行上述软件的一个最小的系统容量总共仅需内存96K字节。
...
展望:
    有这样一种说法:UNIX系统的成功很大程度上归功于它并不是设计来迎合任何规定的目标。当我们中的一个人(Thompson)不满意所用的计算机设施,而发现了很少使用的PDP-7时,就写了第一个版本,并又着手创建一个更为宜人的环境。这种(基本上是一个人的)努力获得圆满成功,从而引起了另一个作者和几个同事的兴趣。稍后,证明用PDP-11/20明确地支持正文编辑和格式加工系统是适合的。后来又突破了11/20,而上述系统证明很有用,足以劝说管理者投资PDP-11/45,后来又投资PDP-11/70以及Interdata8/32机器,以这些为基础发展到现在这种形式。明确说起来,我们整个工作的目标是要与机器建立舒适的关系。并且在操作系统和其它软件中开拓思想和发明。我们还没有碰到那些满足某些人专门请求的需要,我们由于有这种自由度而感到高兴。
    回顾起来,影响设计UNIX系统的有三个方面:
    第一,因为我们是程序员,自然设计这个系统要使得程序容易书写、调试和运行。为了程序设计方便,我们提出的最重要的要求是系统对交互使用的安排,即使原先方案只支持一个用户也是如此。我们认为适当地设计交互系统比成批系统在使用中更加有效和令人满意。而且,在这样一个系统相当容易适应非交互使用,但反过来就不行了。
    第二,这个系统和它的软件始终严格控制其长度,仅为合理的效率和表现能力而局部地放宽了要求。这种长度的约束不仅有利于节约,而且也促进了设计上的雅致。这就使我们在各种困难的矛盾中,抓住了要害,取得了较好的成绩。
    第三,差不多从一开始就注意到系统能够做到自身维护。这一点比想象的更为重要。如果强制系统设计者使用那个系统,那么他们很快就会注意它的功能上和表面上的缺陷,就会强制地推动他去改正缺陷而不至于太晚。因为所有的源程序总是可得到的,且易于连机修改,所以当别人创造、发现和建议新思想时,我们会乐意修改和重写这个系统和它的软件。
    本文讨论的UNIX各个方面至少明显地吸取这些设计考虑的前两点。例如,从程序设计观点来看,对文件系统的接口是非常方便的。所设计的最低一级接口消除了各设备和文件之间以及直接存取和顺序存取之间的差别。没有大的“存取方法”例行程序去要求程序员与系统调用隔绝;实际上所有的用户程序不是直接调用系统,就是使用一个小的库程序,每个程序都小于一页长,它缓冲许多字符,并一次读或写所有这些字符。
    程序设计方便性的另一重要方面是根本不存在一个哪怕是局部地依赖着文件系统或其他系统调用,并局部地受它们维护的复杂结构的控制块。一般说来,一个程序地址空间的内容是该程序的属性,我们力图避免在那个地址空间内的数据结构上设置限制条件。
    系统中所有程序都应该能使用任一文件和设备作为输入或输出,给出上述要求后,还希望把和设备有关的考虑放入操作系统之中。唯一可选择的方案似乎是把每个设备处理的例行程序都装入,这样做在空间上是浪费的;要不就采用某些动态连接的方法,当真正需要时,动态连接适应于每一设备的例行程序,这样做不是在开销方面的浪费,就是在硬件上的浪费。
    同样,进程控制机制和命令接口以证实是方便且有效的。因为shell作为一个普通的、可交换的用户程序操作,它消耗的不是系统本身的空间,而是以小的代价做的像所希望的那样强有力。特别是,我们给出了总的框架结构,shell以这种结构作为一个进程来执行,这个进程又派生出其他进程来完成命令的执行;输入输出重定向、后台进程、命令文件以及用选用的系统接口等概念的实现以完全成为为不足道的了。
    UNIX系统的成功,与其说是有新的创造,还不如说是谨慎地选择一组与其他系统中的完美思想,然后进行充分地开拓,特别是显示了,这些思想可能是实现一个小而功能强的操作系统的关键。
    当我们实现fork操作时GENIE分时系统中已提供了这个操作。在许多地方我们受到了Multics的影响,Multics中提出了输入输出系统调用的特殊形式,并且既有shell的名字,又有它的一般性功能。shell为每个命令建立一个进程的想法也是早先设计Multics时提出来的,然而在那个系统中由于效率的原因后来放弃了这种想法,但一种类似的机制却在TENEX中使用了。

K.Thompson, UNIX系统的实现

    UNIX内核由10000行左右的C语言代码和1000行左右的汇编语言代码所组成。汇编语言代码又可以进一步分成两部分:一部分为200行,它包括不能用C语言写的、执行硬件功能的那些代码。
    这些内核代码占所谓“UNIX操作系统”那一大块程序的5% - 10%。内核是UNIX系统中仅有的不能由用户自己所喜爱的程序去代替的那部分代码。基于这个原因,内核应尽可能地少做一些实际的决定。这一点并不意味着允许用户成千上万种选择去做同一件事情,而是只允许用一种方法去做一件事情,但是这种方法是可能提供的所有选择(方法)中的最集中的公共部分。
    在内核中实现什么或者不实现什么,这既代表了一种极大的义务,也代表了一种极大的能力。在这里,向公众演示了应该如何完成各项工作的方法。尽管如此,如果所述方法太偏激了,那么也就没有人会去照它做了。因此,对每一项重要的决定都要仔细、慎重地权衡利弊,在考虑简单和高效之间,自始至终以简单性代替高效性。对于一些复杂的算法,只有当它们的复杂性有可能被局部化时,我们才采用它们。...

S.C.Johson, 可移植的C语言编译程序综述

引言
    C语言编译程序已经实现了,它已被证明有相当强的可移植性。它可以在大约十几个机器上作为C语言编译的基础,...
    已实现的语言与目前PDP-11上的C语言版本是高度兼容的,而且编译程序的75%(其中包括了所有的语法和语义子程序)是与机器无关的。...
    大部分早期可移植的编译程序都是这样进行的,即定义一种以三地址代码或堆栈式机器代码为基础的中间语言,编写一个与机器无关的程序来将源语言代码翻译成这种中间代码。然后由第二趟扫描读入中间代码,加以解释或编译。这种方法很巧妙,具有许多优点,尤其是在目标机与宿主机差别很大的情况下更是如此。但它也有一些缺点。以和机器无关的方式来表达某些像初始化、子程序开始这样的结构相当困难,或者开销很大,而为了使这些结构能容易地移植为目标机汇编程序,表达方式必须和机器无关。这类方法大多数要求在第二趟(与机器有关)扫描中构造一个符号表,并且(或者)要求功能很强的目标机汇编程序。还可以产生许多对给定的机器毫无作用、但其他机器却可能需要的转换操作符。(例如,指针到指针的转换,一般在C语言中什么也不做,但却必须产生,因为在有些机器上,它们是有意义的)。
    由于这些原因,可移植编译程序的第一趟扫描是不完全独立于机器的。它含有一些与机器有关的特点。例如,初始化、子程序开始及结束、一定的分配功能、开关语句的代码以及去掉不需要的转换操作符的代码。
    根据实际获得的可移植程序的粗略估算,Interdata8/32上C语言编译程序的第一趟扫描,4600行源程序中大约600行与机器有关,在第二趟的3400行中,有1000行与机器有关。总计,在总共8000行源程序中有1600行与机器有关,占20%。其中第一趟占12%,第二趟占30%。在调整该编译程序时,可以预料这些百分比还会有所提高。在IBM370上,与机器有关的代码是22%,在Honeywell上是25%。如果所有这些机器的汇编语言格式和结构都一样,那么大概这些与机器有关的代码中的5%到10%会成为与机器无关的。这些数据很容易使人误解为几乎是无意义的。大部分与机器有关的代码能够以直接的几乎是机械的方式进行转换。另一方面,一部分代码需要用艰苦的脑力劳动来转换,因为这部分代码中所包含的算法特别复杂并且与机器有关。
    总之,如果需要为某一结构合理的机器写C语言编译程序,那么这个编译程序的3/4是现成的。
    ...