1.1.5 UNIX
UNIX/Linux基本结构
图1-3绘出了UNIX系统的高层次的体系结构。图中心的硬件部分向操作系统提供基本服务。操作系统直接与硬件交互,向程序提供公共服务,并使它们同硬件特性隔离。当我们把整个系统看成层的集合时,通常将操作系统称为系统内核,或简称内核,此时强调的是它同用户程序的隔离。因为程序是不依赖于其下面的硬件的,所以,如果程序对硬件没做什么假定的话,就容易把它们在不同硬件上运行的UNIX系统之间迁移。比如,那些假定了机器字长的程序就比没假定机器字长的程序更难以搬到其他机器上。外层的程序,诸如shell及编辑程序(vi),是通过引用一组明确定义的系统调用而与内核交互的。这些系统调用通知内核为调用程序做各种操作,并在内核与调用程序之间交换数据。图1-3中出现的一些程序属于标准的系统配置,就是大家所知道的命令。但是由名为a.out的程序所指示的用户自有程序也可以存在于这一层。此处的a.out是被C编译程序产生的可执行文件的标准名字。其他应用程序能在较低的程序层次之上构筑而成,因此它们存在于图1-3的最外层。比如,标准的C编译程序cc就处在图1-3的最外层;它引用C预处理程序、两次编译程序、汇编程序及装入程序(称为连接-编译程序),这些都是彼此分开的底层程序。虽然图1-3对应用程序只描绘了两个级别的层次,但用户能够对层次进行扩充,直到级别的数目适合于自己的需要。确实,为UNIX系统所偏爱的程序设计风格鼓励把现存程序组合起来去完成一个任务。
一大批提供了对系统的高层次看法的应用子程序及应用程序,诸如shell、编辑程序、SCCS(Source Code Control System)及文档准备程序包等,都逐渐变成了"UNIX系统"这一名称的同义语。然而,它们最终都使用由内核提供的底层服务,并通过系统调用(System Call)的集合利用这些服务。系统调用的集合及其实现系统调用的内部算法形成了内核的主体。简言之,内核提供了UNIX/Linux系统全部应用程序所依赖的服务,并且内核定义了这些服务。下面我们将进一步介绍内核,对内核的体系结构提出一个总的看法,勾画出它的基本概念和结构,这将帮助读者更好地学习以后的内容。
图1-4给出了内核的框图,显示出了各种模块及它们之间的相互关系,它特别指出了内核的两个主要成分:左边的文件子系统和右边的进程控制子系统。虽然实际上,由于某些模块同其他模块的内部操作进行交互而使内核偏离该模型,但该图仍可以作为观察内核的一个有用的逻辑观点。在图1-4中我们看到了三个层次:用户、内核及硬件。系统调用与库接口体现了图1-4中描绘的用户程序与内核间的边界。系统调用看起来像C程序中普通的函数调用,而库把这些函数调用映射成进入操作系统所需要的源语。然而,汇编语言程序可以不经过系统调用库而直接引用系统调用。程序常常使用像标准I/O库这样一些其他的库程序以提供对系统调用的更高级的使用。由于在编译期间把这些库连接到程序上,因此,以这里的观点来说,这些库是用户程序的一部分。
图1-3 UNIX系统的高层次的体系结构
图1-4 UNIX系统内核结构
图1-4把系统调用的集合分成与文件子系统交互作用的部分及与进程控制子系统交互作用的部分。文件子系统管理文件,其中包括分配文件空间、管理空闲空间、控制对文件的存取,以及为用户检索数据。进程通过一个特定的系统调用集合,比如通过系统调用open,close,read,write,stat,chown及chmod等与文件子系统交互。文件子系统使用一个缓冲机制存取文件数据,缓冲机制调节在核心与二级存储设备之间的数据流。缓冲机制同块I/O设备驱动程序交互作用,以便启动往核心去的数据传送及从核心来的数据传送。设备驱动程序是用来控制外围设备操作的核心模块。块I/O设备是随机存取存储设备,或者说,它们的设备驱动程序使得它们对于系统的其他部分来说好像是随机存取存储设备。
例如,一个磁带驱动程序可以允许核心把一个磁带装置作为一个随机存取存储设备看待。文件子系统可以在没有缓冲机制干预的情况下直接与"原始"I/O设备驱动程序交互作用。原始设备,有时也被称为字符设备,包括所有非块设备。进程控制子系统负责进程同步、进程间通信,存储管理及进程调度。当要执行一个文件而把该文件装入存储器中时,文件子系统与进程控制子系统交互:进程子系统在执行可执行文件之前,把它们读到内存中。输入/输出存储管理模块控制存储分配。
在任何时刻,只要系统没有足够的物理存储供所有进程使用,核心就在内存与二级存储之间对进程进行交换,以便所有的进程都得到公平的执行机会。调度程序模块把CPU分配给进程。该模块调度各进程依次运行,直到它们因等待资源而自愿放弃CPU,或者知道它们最近一次的运行时间超出一个时间量,从而核心抢占它们。于是调度程序选择最高优先权的合格进程投入运行;当原来的进程成为最高优先权的合格进程时,还会再次投入运行。进程间通信有几种形式,从时间的异步软中断信号到进程间消息的同步传输等。