Unix Time Sharing System——Unix分时系统翻译

Unix是一个用于通用的、多用户、交互式的操作系统,为DEC的PDP-11/40和PDP-11/45所设计。它具有在大型操作系统上罕见的许多特点,这些特点包括:
(1)多层级的文件系统,具有 可分离的卷
(2)可兼容的文件、设备及内部处理I/O;
(3)初始化异步进程的能力;
(4)对每个用户都可选的系统命令行语言;
(5)用多种语言实现的超过100个子系统;
本文将讨论文件系统和用户命令行接口的特点及实现;
关键词:分时,操作系统,文件系统,命令行语言,PDP-11

1.概述
Unix有3个版本。最早的版本(大约在196%-1970年之间)运行在DEC的PDP-7和PDP-9上。第二个版本运行在未受保护的PDP-11/20上。本文仅描述的PDP-11/40/45系统较为现代,与早期的设备有许多不同。比起较早的Unix,也对一些缺陷进行了重新设计。

PDP-11 Unix自1971年2月开始可运行,起初安装了大约40套。它们都比我们这里描述的系统要小。其中大部分都涉及到具体的应用,例如处理和格式化专利申请,或其他的文字材料。对大量基于Bell系统的交换机故障数据的收集和处理。记录和检查电话服务命令。我们自己的安装主要用于操作系统、编程语言、计算机网络及其他计算机科学方面的研究,当然也用来处理文档。

或许Unix所达到的一个最重要的目的,是展示了一个强大的交互式操作系统不需要那么昂贵的设备或人力维护。Unix能够运行在少于40,000美元的硬件设备上,不到2人年的系统软件投入。但是Unix包含了许多在大兴系统中少见的特性。用户将会发现,这些重要的特性在Unix系统中的实现是简单的、优雅的、易用的。

除了操作系统本身,Unix上可用的主要程序包括:汇编程序、基于QED的文本编辑器、链接加载器、符号调试器、像BCPL一样具有类型和结构的语言编译器、一个BASIC方言的解释器、文本格式化程序、Fortran编译器、 Snobol语言(String Orientated Symbolic Language)解释器、自顶向下的编译程序的编译器、自底向上的编译程序的编译器、表单字母生成器、宏处理器(M6)、排列索引程序。

还有许多可维护的、实用的、全新的程序,这些程序都是本地编写的。值得注意的是系统是自支持的。所有的Unix软件都在Unix下维护,同样地,Unix的相关文档也是通过Unix编辑器和文字格式化程序产生和格式化的。

2.软硬件环境
我们安装Unix的PDP-11/45,是一个16位字长(8bit一字节),具有144K字节核心内存的计算机。Unix占用了其中的42K字节。然而这个系统包括大量的设备驱动和I/O缓冲区,及系统表的通用可分配空间。具有运行上述所有软件的能力的系统,最低仅仅需要50K字节的核心。

PDP-11有 1M字节的固定磁头磁盘,用于文件系统的存储和交换,4个可移动磁头磁盘驱动器,每个可移除磁盘盒提供2.5B字节。还有1个单独的可移动磁头的、采用了可移除的40M磁盘包的驱动器。还有一些高速打孔纸带阅读器,9磁道磁带,以及DEC磁带(记录可以被寻址和重写的,有大量磁带功能)。除了控制台打字机,还有用于假脱机输出到公用行打印机的14个可变速通讯接口附加在100系列数据集和201数据集接口。其他一些设备包括可视电话接口,音频反馈单元,音频同步器、照相排字机、数字交换网络、和在一个随PDP-11/20产生向量、曲线、字符并在Texktronix 611展现的 存储显像管。

Unix的大部分是由上面提到的C语言编编写。早期版本的操作系统是用汇编语言编写。但是1973年夏天之后,用C语言重写了一遍。新系统的体积比老版本大3倍。新的系统不仅更易于理解和修改,而且包括了很多函数的改进——例如多道程序和在多用户程序之间共享的代码可重入功能的能力。我们认为由此带来的体积增长是完全可接受的。

3.文件系统
Unix最重要的是引入了文件系统的角色。从用户的角度,有3种类型的文件:普通的磁盘文件,目录,以及特殊文件。

3.1普通文件
一个文件可以包含用户放置的任何类型的信息,例如符号或者二进制对象或程序。系统不需要特定的数据结构。文本文件包含简单的、由换行符分隔段落的字符串。二进制文件是当程序开始执行时,将会在核心内存中顺序存放的字的序列。少数的用户程序会通过更多的结构操作文件:汇编生成器和加载器需要特定格式的对象文件。即便这样,文件的结构也是由使用它们的程序控制的,而不是系统。

3.2目录
目录提供了文件名和文件本身的映射方式,并包含了文件系统上的一个整体结构。每个用户都有一个自己的文件目录。同样,用户也可以创建许多包含一组文件的子目录。一个目录的行为和一个普通文件是相同的,除了它不能被无权限的程序写入,因为目录的内容是由系统控制的。任何人有适当的权限都可以读取一个目录,就像读取文件一样。

Unix系统中有一些系统自身用到的目录。其中之一是根目录。系统中所有的文件都可以通过追踪一个链条一样的目录路径找到,查找的起点经常是根目录。另一个目录包含了供一般使用的通用程序,即所有的命令。但是后面将会看到,为了执行而将一个程序放置在这个目录中是没有必要的。

文件名由不多于14个字符组成。系统中的文件名以路径名的格式组成,这是由多个通过"/"分隔的目录名序列加以文件名结尾。如果这个序列是以"/"开头,查找就会从根目录开始。例如/alpha/beta/gamma这样的目录在查找时,系统会先在根目录下寻找alpha目录,然后在alpha目录中查找beta目录,最后在beta目录中查找gamma目录。gamma可能是一个目录、普通文件或特殊文件。作为一个特定的例子,"/"指的是根目录。

一个路径如果不是以"/"开头,系统在查找时就会从用户的当前目录中开始。例如alpha/beta,意味着beta文件位于用户当前目录下的alpha子目录。作为另一特定的例子,空文件名指的是当前目录。

同一个非目录文件可能位于不同的目录下,具有不同的名字。这种特性叫做链接。一个文件的目录条目有的时候也叫做链接。Unix不同于其他系统的是,允许所有到同一文件的链接都具有相同的状态。这就是说一个文件不存在于一个特定的目录下。即一个文件的目录条目仅仅包含名称和指向实际描述文件信息的指针。因此一个文件独立于任何目录条目而存在,尽管实际上文件会随着最后的链接而消失。

每个目录通常都有两个条目。"."在每个目录中都表示当前目录。因此程序可以通过"."读取当前目录而不需要指定完整的目录路径。".."表示当前目录的父目录。

目录结构是一个有根的树。除了特殊的条目"."和".."以外,每个目录必须仅表示为一个在其他目录(即父目录)下的条目。这样做的目的是简化程序访问目录结构中子树的写法。更重要的是,这样能够避免从整棵树上分离层次结构。如果允许任意到目录的链接,自从上次从根到一个目录的链接被断开后,查找就会变得很困难。

3.3特殊文件
特殊文件组成了Unix文件系统大部分不同寻常的特性。Unix支持的每种I/O设备都被关联到这样的一个特殊文件。特殊文件的读写就像普通的磁盘文件一样。但是读或写的结果是在实际关联的激活设备中。特殊文件对应的条目在/dev目录下,链接到这类特殊文件也像一个普通文件一样。例如,给纸带打孔就会写文件/dev/ppt. 每一条通信线路,每个磁盘,每个磁带驱动以及核心物理内存都会有对应存在的特殊文件。当然,活动磁盘和核心特殊文件是受保护不会被随意访问的。

这样处理I/O设备有3个好处:文件和I/O设备尽可能相似;文件和设备有相同的语法及含义,这样程序中就可以将设备名像文件名一样作为参数传递。最后,常规文件适用的保护机制一样适用于特殊文件。

3.4可移除文件系统
尽管文件系统的根总是存放在相同的设备上,整个文件系统层级都驻留在设备上是没有必要的。一个mount系统请求有2个参数:一个已存在的普通文件名,一个可以直接访问的特殊文件名,这个文件相关联的卷(例如磁盘包)可以有包含自己目录层级的独立的文件系统结构。mount所达到的效果是,像引用一个普通的文件一样访问位于可移除的卷上文件系统的根目录。事实上,mount用位于可移除的卷上的完整子树替换了树形层级中的一个叶结点。通过mount,在可移动卷上和永久文件系统上的文件事实上没有区别。在我们的安装中,根目录驻留在固定磁头的磁盘上。包含了用户文件的较大的磁盘驱动器被系统初始化程序挂载,4个小一点的磁盘驱动器挂载它们自己的磁盘后也对用户可用。1个可挂载的文件系统是通过写对应的特殊文件产生的。可用通过通用程序创建空文件系统,也可以拷贝一个已存在的文件系统。

在用相同的处理方式对待处于不同设备上的文件的时候,只有一个例外:不同的文件系统层次之间不能有链接。这种强制性的约束,是为了避免在卸载可移除的卷时,移除链接所需要的复杂计算。特别要指出的是,无论是否在可移除的文件系统上,对于根目录而言,".."值得是当前目录本身,而不是父目录。

3.5保护
尽管Unix的访问控制定义非常简单,但是很有特点。每个用户被分配了一个唯一的用户标识符。当文件被创建的时候,文件被标志出所有者的ID。文件的保护是通过一组7位二进制数实现的。其中6位对文件的所有者和其他用户单独控制文件的读、写、执行权限。

如果第7位被置为1,无论何时文件被作为程序执行,系统会临时改变当前用户的用户标识符为文件的创建者。这种对用户ID的修改只有在调用它的程序被执行的时候有效。设置用户ID的特性,给那些无法访问文件的用户程序提供了特权。例如,一个程序记录了一个文件,除了这个程序本身,谁也不能读或改写这个文件。尽管其他程序被禁止访问该文件,但如果设置用户标识位被这个程序置位,这个文件就能够被其他程序访问,尽管这些程序的调用者用户是禁止访问该文件的。
 

除了后面将要提到的,读和写都是顺序的。即如果从文件中写入或读取了某几个字节后,下一次I/O调用指向的是紧接着的字节。每个文件都有一个由系统维护的指针,来表示下一个即将读取或写入的字节位置。如果读取或写入了n字节,指针就会前进n字节。

打开一个文件后,以下调用会被用到:
n = read(filep,buffer,count)
n = write(filep,buffer,count)  
        
在由filep指定的文件和由buffer指定的字节数组之间传输count个字节。返回值n是实际传输的字节数。在写操作时,n与count是相等的,除了I/O错误,或者到达物理介质的末尾。在读操作时,n在不出现异常的情况下是小于count的。如果读指针已经接近文件末尾,读取count个字节可能会超出文件末尾。在此情况下,只有从读指针到文件末尾的字节是有效返回的。同样的,类打字机的设备不会返回来自输入的多于1行的内容。当读操作的返回值n等于0时,表示已经到达文件末尾。对于磁盘文件,这表示读指针已经到达了文件体积的上限。通过一个Esacpe序列可以在打字机上产生end-of-file标识,当然具体情况取决于具体的设备。

写入一个文件的字节,只会影响到通过写入指针和count(写入字节数)计算得出的文件中的那些对应位置的内容。其他位置的内容不会发生改变,如果写入的最后一个字节超过了文件末尾,文件体积就会应需增长。

对于可随机(直接访问)I/O,只有将读、写指针移动到恰当位置的必要。
location = seek(filep,base,offset)

以base为基准,通过offset指定的偏移量,filep对应的文件指针可以从开始、当前位置、结尾移动offset个字节的位置。在一些设备中,例如纸带机和打字机,seek操作会被忽略。通过seek操作实际移动到的位置通过location返回。

3.6.1其他的I/O调用
其他关于I/O和文件系统的操作不再深入讨论。例如:关闭文件、获取文件的状态、更改文件的保护模式或所有者、创建目录、链接到已有文件、删除文件等。

4.1文件系统的实现
正如3.2节中提到的,一个目录条目包含一个关联到文件的名字和一个指向自身的指针。这个指针是一个叫i-number的整型数。当文件被访问时,它的i-number被用作系统表(i-list)的索引——系统表存储在目录所在设备的已知部分。由此找到的条目包括关于文件的以下描述信息:
1.所有者;
2.保护位;
3.文件内容的物理磁盘或磁带的地址;
4.大小;
5.上次修改时间;
6.到文件的链接数,也就是文件在目录中出现的次数;
7.一个表示文件是否是目录的bit;
8.一个表示文件是否属于特殊文件的bit;
9.一个表示文件是“文件”还是“小文件”的bit;

open或create系统调用的目的是,通过查询显式或隐式命名的目录把用户指定的路径名称转换为i-number。文件一旦被打开,它所在的设备、i-number、读/写指针都被存储在系统表中。系统表通过open和create返回的文件描述符索引。因此文件描述符能够很容易的与随后可能用到的read、write系统调用访问文件时所需的信息关联。

创建一个新文件时会分配一个i-node给新文件,同时创建一个包含文件名和i-node编号的目录条目。建立一个到现有文件的链接时,会用新文件名创建一个新的目录条目,从源目录条目拷贝i-number,增加i-node中的link-count值。删除文件时,会减少目录条目对应的i-node中的link-count,然后抹去目录条目。如果link-count减为0,文件的所有磁盘块都被释放,i-node也被重新分配。

所有固定或可移除磁盘的空间都被划分为512字节的块,地址编号从0到设备本身的容量上限。每个文件的i-node中都为8个设备地址留有空间。一个小文件(非特殊文件)适合于8个或更少的块,在此情况下块的地址本身被存储。对于大文件(非特殊文件),8个设备地址中的每一个, 都指向一个256个块地址组成的文件本身。 这些文件可以大到8*256*512=1,048,576(2的10次方)字节。

前面的讨论都是针对普通文件的。当对一个i-node显示是特殊文件的I/O请求时,其他的7个设备地址字就不重要了。列表被解释为组成内部设备名称的字节。这些字节确定了各自的设备类别,并由此决定由哪个系统程序来处理该设备的I/O。子设备编号选择了例如附加在一个指定的控制器上的1个磁盘驱动器,或多个相同的打字机接口之一。

在此情况下,mount系统调用的实现非常简单。mount维护一个系统表,其参数是mount过程中,i-number和指定的普通文件设备名称,匹配的值是设备名称。这个表用于在open和create时扫描的路径名称所转换的(i-number,device)对的查询。如果找到匹配的对,i-number被替换为1(这是所有文件系统上的根目录的i-number),设备名被替换为表的中的值。

对于用户而言,文件的读写都是同步和没有缓存的。在read系统调用返回后,数据马上可用。而且很方便的是,在write系统调用之后,用户的工作空间可以重复使用。实际上系统维护了一个复杂的缓存机制,来大幅度降低访问文件所需要的I/O操作数。假定write系统调用是传输指定的单一字节。

Unix会查找缓冲区以确定受影响的磁盘块当前是否在核心内存中。如果不是,将从设备上读取。缓冲区中的对应的字节被替换,然后在待写入块列表中创建一个条目。write系统调用返回,尽管实际上I/O会晚一点才完成。相反的是,如果读取一个单独的字节,系统会确定该具有该字节的二级存储块是否已经在缓冲区中,如果是,该字节会被立刻返回。如果不是,这个块将被读取到缓冲区,然后取出该字节。

以512字节为一个单元读取文件的程序优于一次读写一个字节的程序,但获益不是很高,它主要来自于避免过多的系统开销。一个极少使用或者没有巨大的卷的I/O,以较小的单元读写就比较合理。

i-list是Unix一个非同寻常的的概念。实际上,这种组织文件系统的方法更加可靠和易于处理。对于系统自身而言,有一个优势是每个文件都有一个短的,无歧义的名字,可以简单的方式与保护、寻址、及其他访问文件所需的信息相关联。其同样允许通过一个简单快速的算法,来检查文件系统一致性,例如,验证每个设备包含有用信息的部分、分离或合并设备上已使用的空间。这个算法不依赖目录的层级关系,它只需要扫描线性的i-list。同时,i-list引起了某些单独的特性,这在其他文件系统中是没有的。例如,既然一个文件的所有目录条目都具有相同的状态,谁应该负责文件所占用的空间。文件的所有者负责是不公平的,总的来说,既然一个用户可能会创建文件,另一个用户可能会链接到它,而第一个用户可能会删除文件。第一个用户仍然是文件的所有者,但是他应该对第二个用户负责。最简单公平的算法是由链接到文件的用户均摊。当前版本的Unix避免了这个问题。

4.1文件系统的效率
为了提供对Unix和文件系统的指示,我们分析一个7621行的汇编程序的时间。该汇编程序独自在机器上运行,总体的时钟时间是35.9秒,每秒运行212行。时间被按照如下方式划分:63.5%的时间用于汇编的执行,16.5%的时间是系统开销,20%的时间是磁盘的等待时间。我们不视图解释这些数字,也不会去和其他系统对比,只是说我们总体上对于这样的系统开销是满意的。

5 进程和印象
印象是一个计算机执行环境。它包括核心印象,通用寄存器值,打开的文件状态,当前目录,以及与此相似的东西。印象是一个伪计算机的当前状态。

进程是一个印象的执行。当处理器代表一个进程去执行时,印象要驻留在核心内存中。在其他进程的执行过程中,它仍然驻留在核心内存中,除非一个激活的,更高优先级的进程强制性的把它从内存中交换到固定磁头的磁盘驱动器上。

一个印象的用户核心部分在逻辑上分成3段。程序文本段从虚拟地址空间的0开始。在执行过程中,这个段是写保护的,而且它的单一拷贝被所有执行相同程序的进程所共享。从最初开始,程序文本段的8K字节处,是一个可写的、非共享的数据段。这个段的体积可以通过系统调用扩展。在虚拟地址的最高处开始的是栈段,当栈指针变动时,它自动向下增长。

5.1进程
除了Unix引导它自身进入运行中,只能通过使用fork系统调用创建一个新的进程。

processid=fork(label)

当一个进程执行fork系统调用,它会被分离成两个独立的执行进程。这两个进程有各自独立的源印象的拷贝,并共享所有打开的文件。新进程唯一不同于父进程的是:在父进程中,控制从fork直接返回,在子进程中,控制被传递给label.fork系统调用返回的processid是相对于其他进程的标识。

因为父进程和子进程的返回点不同,fork后的每个印象都可以决定它是父进程还是子进程。

5.2 管道
进程可以与相关的进程用和文件系统相同的read/write系统调用方式通信.

filep=pipe()

这个系统调用返回一个文件描述符filep,并创建一个叫做pipe的进程间通道。这个通道就像打开的文件一样,在印象中通过fork调用从父进程传递到子进程。read调用使用管道文件描述符,等待其他进程使用同样的管道文件描述符写入。在这点上,数据是在两个进程的印象之间传递的。进程不需要了解管道比普通文件的区别,只需要调用它。

5.3程序的执行
另一个主要的系统原语是

execute(file,arg1,arg2,…,argn)

该调用请求系统读入并执行名为file的程序,并传递字符串类型的参数arg1,arg2,...argn.一般的arg1与file相同,因此程序可以确定被调用的名称。用execute执行的进程中所有的代码和数据,都被file所替代。但是打开的文件、当前目录、进程间的关系是不变的。只有当调用失败时,例如找不到file对应的程序文件,或由于这个文件的执行许可位(execute-permission bit)没有被置位,才会从execute原语返回。这很像机器指令中的jump,而不是子程序的调用。

5.4进程同步
另一个进程控制的系统调用

processid=wait()

这个调用导致它的调用者将执行挂起,直到它的某个子进程执行结束。wait返回终止进程的processid。如果调用的进程没有后代进程,会返回error。子进程的某些状态也是可用的。wait可以获取到孙子或更远祖先进程的状态。

5.5终止
最后,

exit(status)

这个系统调用终止一个进程,销毁其印象,关闭打开的文件,抹去这个进程。当父进程通过wait原语被通知,参数status所指示的状态就可用了。如果父进程已终止,其状态对祖父进程可用,以此类推。进程也可能由于一些非法动作或用户产生的信号终止。

6.Shell
对于大部分用户,与Unix的沟通都是通过一个叫做Shell的程序辅助完成的。Shell是一个命令行解释器:它读取用户输入的行,然后解释它们为请求执行的程序。在最简单的情况下,一个命令行由命令名和跟随的参数组成,命令名和参数之间通过空格分隔。

command arg1 arg2 … argn

Shell将命令名和参数分割为独立的字符串,这样就能找到名为command的文件。command可能是一个包含"/"的路径名以指出系统中的任何文件。如果command被找到,它将被引入到核心内存中被执行。Shell收集到的参数对于command是可访问的。Shell重新回到自己的执行当中,并立刻准备接受用户输入的下一条命令。

如果没有找到command对应的文件,Shell会自动在command前添加/bin/,来试图从/bin目录下再次寻找。/bin目录中包含了常用的命令。

6.1标准I/O
前面讨论过的I/O表明每个程序用到的文件都必须通过程序打开或创建以获取文件描述符。通过Shell执行的程序,是以两个打开的文件描述符为0和1的文件开始的。这样的程序开始执行时,文件1用于写,可以理解为标准的输出文件。除了以下情况,即文件是用户的打印机。程序希望通过文件描述符1写入有用的,或调试用的信息。相反的,文件0用于读取,程序希望读取用户输入的信息。

Shell能修改标准分配的键盘或打印机文件描述符。如果command的一个参数是以">"开头,文件描述符1在command执行中就会被替换为>后面跟随的文件名。例如:

ls

一般会在打印机上列出当前目录中的文件。命令:
ls >there
会创建一个there文件,然后把文件列表作为文件内容填进去。因此参数 ">"表示把输出放到there中。另一面

ed
一般会进入编辑器,通过用户的打字机获取请求。命令:

ed<script

把script作为编辑器命令的文件解释。"<script"意味着,从script获取输入。

尽管"<"">"后面跟随的文件名作为命令参数出现,事实上它会被Shell作为命令解释,而不会作为参数传递给前面的命令。因此,没有在每个command中处理重定向的必要。命令只要在适当的时候使用标准的文件描述符0和1即可。

6.2Filters
标准I/O概念的一个扩展,是将一个命令的输出用做另一个的输入。1个用竖线分隔的命令序列会使Shell同时执行所有的命令,并同时把每个命令的输出作为下一个命令的输入。在命令行中:
 ls |pr -2|opr
ls列出当前目录中的所有文件名;它的输出被传递给pr,这个命令可以把输入分页,并在页眉显示日期。参数“-2”表示显示2列。同样的,pr的输出作为opr的输入。这个命令把它的输入假脱机到一个离线打印的文件上。

这个过程也可以通过一个更笨拙的方式实现
ls>temp1
pr -2<temp1 >temp2
opr <temp2

在没有重定向input和output的能力时,一个更笨拙的办法是接受用户的请求来分页其输出,把它按照多列打印,然后将输出传输到脱线。事实上期望ls命令的作者提供如此之多的命令选项,这会让人很诧异,而且既不高效也不明智。

类似pr的程序把它的标准输入拷贝到标准输出的操作,叫做过滤器(filter)。过滤器在我们处理字符串的直译、输入的排序、编码和解码上是很有用的。

(未完)


本作品采用知识共享署名-非商业性使用-禁止演绎 3.0 未本地化版本许可协议进行许可。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值