第3章 操作系统的用户接口

3.1 用户工作环境

现代操作系统提供了多用户工作环境,众多用户可以在操作系统的支持下完成各种应用任务。采用虚拟技术,系统可为每个用户提供一个工作环境,这将保证各个用户之间是隔离的,即用户不会干预这个系统中其他用户已开始的工作。而且,用户还可以根据不同的应用需求,选择不同类型的操作系统,如炼钢生产过程控制可选择实时操作系统以获得实时控制的能力。因为不同类型的操作系统有不同的特征,具有各自能提供的恰当的服务,即操作系统具有能满足不同工作需要的用户工作环境。

3.1.1 操作系统提供的环境

操作系统应为用户提供一个工作环境,形成用户环境包含下面三个方面的内容。

① 提供各种软、硬件资源。
② 设计操作系统的命令集(包括操作命令和系统功能调用)。用户通过查阅操作系统提供的“操作说明书”和“程序员手册”了解操作系统的用户接口,使用户能方便地控制他所在的系统。
③ 当用户需要的时候,激活操作系统,使它成为一个可以提供服务的系统。这就是系统初启。

下面简述一个交互工作环境。用户在一个终端上操作,他可以发出命令,告诉系统当前他需要的某个服务,操作系统就执行这一用户请求并提交结果。如果这一请求失败,系统会尽可能完全或简要地告诉用户这次失败的原因。当用户要求操作系统处理另一个请求时,就重复上述过程,该过程通常称为终端对话期间。在分时系统中,各个终端用户能同时进行会话处理,每个用户都能和操作系统交谈,并由操作系统同时发送回答。

在多用户操作系统中,需要对每个用户的身份进行合法性检查。通常每个用户都有一个用户标识,它可以是数码或一个字符串。当用户进入系统时,必须以用户标识来标识自己。系统根据用户标识的名字和口令来验证其身份。当验证合法后,系统就可以确定用户享有的特权和应有的限制。

用户通过操作系统命令集可以做很多事,例如,创建一个文件,增加、删除或编辑一个文件,运行一个程序或者列出用户的文件目录。在多用户环境中,用户要退出计算机系统时,必须使用“撤离”命令。用户一旦撤离,就不能发任一命令或存取任一个文件。此时,这个终端也变为不活动的,直到另一个用户再联机进入系统时为止。

3.1.2 操作系统的生成和系统初启

为了激活操作系统,需要进行操作系统的初启工作,即将操作系统装入计算机,并对系统参数和控制结构进行初始化,使计算机系统能够为用户提供用户工作环境。操作系统是一个大型的系统软件,包括程序和数据。在系统初启前,它必须存放在硬盘(或软盘、光盘)的特殊位置上,当系统加电时,才能开始系统初始化过程。但是,还有一个十分重要的问题,那就是操作系统这一大型的软件系统是如何产生的呢?这一问题就是操作系统的生成问题。

1.系统生成

操作系统的生成是形成一个能满足用户需要的操作系统的过程。这一过程只能由计算机厂商或系统程序员在需要时施行。这项工作将决定操作系统规模的大小、功能的强弱,所以它对计算机系统的特性和效率起着很大的作用。

计算机制造商提供一批可供用户选择的系统功能模块和实用程序,另外,还提供一个可以立即执行的系统生成程序,称为SYSGEN。SYSGEN程序通过询问系统程序员有关硬件系统特定的配置信息,或直接检测硬件以确定有什么部件,以获得系统的硬件配置信息。另外,SYSGEN通过与用户的交互,获得用户所希望建立的操作系统的规模、所需系统的功能模块等信息。SYSGEN程序根据获得的已配置的硬件资源和用户所希望建立的系统的功能,确定选择的功能模块,通过连接而生成操作系统主存映像文件。

所谓系统生成,是指为了满足物理设备的约束和需要的系统功能,通过组装一批模块来产生一个清晰的、使用方便的操作系统的过程。系统生成包括:根据硬件部件确定系统构造的参数,编辑系统模块的参数,并且连接系统的目标模块成为一个可执行的程序。

在系统生成过程中,必须确定以下信息。

① 使用的CPU类型,需安装的选项(如扩展指令集、浮点运算操作等)。对于多CPU系统必须描述每个CPU的类型。
② 可用主存空间,有的系统通过访问每个主存单元直到出现“非法地址”故障的方法来确定这一值。该过程定义了最后合法地址和可用主存的数量。
③ 可用的设备,系统需要知道设备类型、设备号、设备中断号及其所需的设备特点。
④ 所需的操作系统选项和参数值。例如,所支持进程的最大数量,需要的进程调度策略的类型,需要的缓冲区的大小等。

这些信息确定后,通过编译内核,生成所需要的操作系统的可执行代码。

2.系统初启

当操作系统生成后,以文件形式存储在某种存储介质(如磁盘)中。这是一个可执行的目标代码文件,它是由C语言和少量汇编语言程序经过编译(或汇编)、连接而形成的。

(1)什么是系统引导
系统初启又叫系统引导。它的任务是将操作系统的必要部分装入主存并使系统运行,最终处于命令接收状态。系统初启在系统最初建立时要实施,在日常关机或运行中出现故障后也要实行引导。
系统引导分为三个阶段。

① 初始引导:把系统核心装入主存中的指定位置,并在指定地址启动。
② 核心初始化:执行系统核心的初启子程序,初始化系统核心数据。
③ 系统初始化:为用户使用系统作准备。例如,建立文件系统,建立日历时钟,在单用户系统中装载命令处理程序;在多用户系统中为每个终端分别建立命令解释进程,使系统进入命令接收状态。

系统引导经过这三个阶段后,已经处于接收命令的状态,用户可以使用操作系统提供的用户接口使用计算机系统了。

(2)系统引导的方式
操作系统的引导有两种方式:独立引导(bootup)和辅助下装(download)。

① 独立引导方式(滚雪球方式)
独立引导方式又称为滚雪球方式,这种引导方式适用于微机和大多数系统。它的主要特点是操作系统的核心文件存储在系统本身的存储设备中,由系统自己将操作系统核心程序读入主存并运行,最后建立一个操作环境。
② 辅助下装方式
这种引导方式适用于多计算机系统、由主控机与前端机构成的系统以及分布式系统。它的主要特点是操作系统的主要文件不放在系统本身的存储设备中,而是在系统启动后,执行下装操作,从另外的计算机系统中将操作系统常驻部分传送到该计算机中,使它形成一个操作环境。

辅助下装方式的优点是,可以节省较大的存储空间,下装的操作系统并非是全部代码,只是常驻部分或者专用部分,若这部分代码出现问题和故障时,可以再请求下装。

3.独立引导的过程

(1)初始引导
初始引导也叫自举。自举的含义是操作系统通过滚雪球的方式将自己建立起来。这是目前大多数系统所常用的一种引导方法。

系统核心是整个操作系统最关键的部分,只有它在主存中运行才能逐步建立起整个系统。初始引导的任务就是把核心送入主存并启动它运行。当系统未启动时并没有文件系统,那么,在初始引导时,如何能在辅存上找到操作系统的核心文件并将它送到主存中呢?这需要设计一个小小的程序做这件事,该程序称为引导程序。然而,这个引导程序也在辅存中,如何将引导程序首先装入主存呢?这需要有一个初始引导程序,而且这个程序必须在一开机时能自动运行,这只有求助于硬件了。

在现代大多数计算机系统中,在它的只读存储器(ROM、PROM、EPROM)中都有一段用于初始引导的固化代码。当系统加电或按下某种按钮时,硬件电子线路便会自动地把ROM中这段初始引导程序读入主存,并将CPU控制权交给它。初始引导程序的任务是将辅存中的引导程序读入主存。这里必须指出,这个引导程序必须存放在辅存的固定位置上(称为引导块),ROM从这个引导块去读内容,而不管它是什么,这就要求将引导程序事先存放在这个引导块上。

初始引导的具体步骤如下。

① 系统加电;
② 执行初始引导程序,对系统硬件和配置进行自检,保证系统没有硬件错误;
③ 从硬盘中读入操作系统引导程序,并将控制权交给该程序模块。

在X86计算机中,当计算机电源被打开时,它会先进行上电自检,然后执行FFFF:0000的BIOS初始引导程序,该程序的执行将寻找启动盘,如果选择从软盘启动,计算机就会读入软盘的0面0磁道1扇区,如果发现它以0xAA55结束,则BIOS认为它是一个引导扇区(Boot Sector),否则报告出错。如果从硬盘引导,则读入的是硬盘的0柱面0磁道1扇区。引导扇区的512个字节包含三个方面的内容:引导程序、磁盘分区表(其中之一标注为活动分区)、引导盘标记。该扇区的内容会被读入到内存的0000:7c00处,随后,CPU执行跳转指令,跳转到0000:7c00处执行引导程序。

(2)引导程序执行
当引导程序进入主存后,随即开始运行。该程序首先查找分区表,找到活动分区,并读入活动分区的第一个扇区,一般称整个磁盘的第一个扇区为主引导块,每个逻辑磁盘的第一个扇区为引导块以示区别。引导块被读入内存后,其程序被执行,该程序的任务是将操作系统的核心程序读入主存某一位置,然后控制转入核心的初始化程序执行。由于现代操作系统往往都很庞大,系统映像可能以压缩格式存放,而引导块又受限于512个字节,实现的功能有限,因此,引导程序也可以是只负责装入引导装入程序(如lilo),再由后者装入操作系统。

(3)核心初始化
操作系统被装入后,核心的初始化程序开始执行,其任务是初始化系统数据结构及参数,具体如下。

① 建立进程有关的数据结构;
② 获得自由存储空间的容量,建立存储管理的数据结构;
③ 建立系统设备和文件系统的数据结构;
④ 初始化时钟。

(4)系统初始化
系统初始化的主要任务是做好一切准备工作,使系统处于命令接受状态,使用户可以使用计算机。

① 完善操作系统的工作环境,装载命令处理程序(或图形用户界面),并初始化;
② 在多用户系统中,为每个终端建立命令解释进程,使系统处于命令接收状态。

4.Linux系统的引导

Linux系统是以滚雪球的方式启动的,通过加电或复位,使BIOS启动(bootsect.s),然后装入引导程序(Boot Loader),实现系统初始化。

(1)系统加电或复位
将主存中所有的数据清零,然后进行校验,若无错,ROM 中的BIOS入口FFFF:0000送入CS:IP。

(2)BIOS启动
在ROM中的引导程序放在固定位置:FFFF:0000,CPU从这里开始执行。

① 上电自检;
② 对硬件设备进行检测和连接,并将测得的数据送入BIOS数据区;
③ 从盘中读入引导程序(Boot Loader)。

从硬盘启动时,读入0柱面0磁道1扇区MBR(Master Boot Record),将控制权交Boot Loader。

(3)引导程序(Loader)执行
引导程序执行,将OS读入主存,并将控制权交给OS的初始化程序。

(4)核心及系统的初始化
Linux系统的核心及系统的初始化工作由Setup.s、Heads和Start_kernel()依次执行来完成。

① Setup.s的主要工作

  • 检查调入主存中的代码 ;
  • 获取内存容量信息,设置设备模式;
  • 屏蔽中断,准备进入保护模式;
  • 设置中断描述符表(idt),全局描述符表(gdt);控制权交给Heads。

② Heads的主要工作

  • 对中断向量表做准备工作;
  • 检查CPU类型;
  • 调用Setup_paging进行页面初始化;
  • 调用main.c中的Start_kernel()。

③ Start_kernel()的主要工作

  • 对与CPU、主存等最基本硬件相关部分进行初始化;
  • 对中断向量表进行初始化;
  • 为进程调度程序做准备;
  • 设置基准时钟;
  • 内核的内存分配;
  • 对文件系统进行初始化;
  • 建立init进程。

init进程对每一个联机终端建立“getty”进程,getty在终端上显示“login”,等待用户登录。当登录提示符出现时,就是通知用户,Linux系统内核已经启动,现在正在运行。

3.1.3 应用程序的处理

1.处理用户程序的步骤

控制计算机工作的一般方法是,由用户在终端设备上键入请求系统资源或处理应用程序的命令。例如,用户可先通过编辑命令在磁盘上建立源程序,接着发编译命令,操作系统接到这条命令后,将编译程序调入主存并启动它工作。编译程序将源程序进行编译并产生浮动的目标程序。然后,用户再发出连接命令,操作系统执行该命令,将生成一个完整的、可执行的主存映像程序。最后发出运行命令,由操作系统启动主存映像程序运行,从而计算出结果。从这个简单的例子可以看到,应用程序通过计算机的若干个步骤的处理后可得到最后结果。

对应用程序加工的过程一般可分为如下4个步骤。

(1)编辑(修改)
建立一个新文件,或对已有的文件中的错误进行修改。

(2)编译
将源程序翻译成浮动的目标代码。完成这一步工作需要有相应语言的编译器,如源程序是C语言写的,那么必须有C编译器。

(3)连接
将主程序和其他所需要的子程序和例行程序连接装配在一起,使之成为一个可执行的、完整的主存映像文件。

(4)运行
将主存映像文件调入主存,并启动运行,最后得出计算结果。

这4个步骤是相互关联、顺序地执行的。具体表现为:① 每个步骤处理的结果产生下一个步骤所需要的文件;② 一个步骤能否正确地执行,依赖于前一个步骤是否成功地完成。一个用户程序的处理步骤如图3.1所示。

图像说明文字

通过编辑器生成的源程序经过编译(或汇编)程序处理后,被翻译成浮动的目标代码。编译过程同时还形成内部符号表和外部调用表,为下一步的连接装配做好准备。内部符号表说明本模块可被其他程序调用的入口点,外部调用表说明本模块要调用的外部模块名。

连接的主要工作是确定本模块和其他所需要的目标模块之间的调用关系,进行地址的连接,形成一个浮动的(从0开始编址)主存映像文件。当该程序要加载到主存运行时,还要经过操作系统的存储管理部件进行地址重定位,才能正确地执行(这部分内容将在第6章讨论)。

随着操作系统技术的发展,对应用程序处理的这4个步骤也发生了变化。为了有效地使用主存,在虚拟存储技术的支持下,现代操作系统采用动态链接技术,如图3.1所示。另外,有的语言处理程序采用软件集成技术(如TRUBO C),将处理步骤集成在一起,提供自动处理能力。

2.静态连接和动态链接

连接这一处理步骤,以前通常采用静态连接方式。静态连接是将所有的外部调用函数都连接到目标文件中形成一个完整的主存映像文件。采用这种静态连接的缺点是,当有多个应用程序都需要调用同一个库函数时,这多个应用程序的目标文件中都将包含这个外部函数对应的代码。这将造成主存的极大浪费,不能支持有效的共享。

动态链接是将这一连接工作延迟到程序运行的时候进行,所需要的支持是动态链接库(DLL)。动态链接不需要将应用程序所需要的外部函数代码从库中提取出来并连接到目标文件中,而是在应用程序需要调用外部函数的地方做记录,并说明要使用的外部函数名和引用入口号,形成调用链表。当所需的动态链接库DLL在主存时,就可以确定所需函数的主存绝对地址,并将它填入调用链表相应位置中。当应用程序运行时,就可以正确地引用这个外部函数了。现代操作系统中已有许多系统采用了动态链接技术(如Windows系统),现在的动态链接库一般是系统库。

3.2 用户接口

3.2.1 用户接口的定义

用户使用计算机处理应用问题时,他最关心的问题是系统提供什么手段使自己能方便地描述和解决问题。用户需要的是使用方便、简单明了且功能强大的手段和方法。例如,各种高级语言、面向对象的程序设计语言及其对应的编译系统,使用方便的操作系统的键盘命令或直观形象的图形用户界面。在现代计算机系统中,用户通过操作系统提供的用户接口或用户界面来使用计算机。

操作系统的用户接口是操作系统提供给用户与计算机打交道的外部机制。用户能够借助这种机制和系统提供的手段来控制用户所在的系统。

操作系统的用户接口分为两个方面:其一,是操作接口,用户通过这个操作接口来组织自己的工作流程和控制程序的运行;其二,是程序接口,任何一个用户程序在其运行过程中,可以使用操作系统提供的功能调用来请求操作系统的服务(如申请主存、使用各种外设、创建进程或线程等)。不论哪一类操作系统都必须同时提供操作接口和程序接口。

操作系统用户接口的形式与操作系统的类型和用户上机方式有关,主要表现在操作接口形式上的不同。用户上机方式分为联机操作和脱机操作两种方式,在联机操作方式下,用户与计算机可以交互会话;而脱机操作方式下,用户不能直接控制程序的运行。所以,批处理系统提供的操作界面称为作业控制语言,因为这类操作系统采用的是脱机处理方式,而分时系统或个人计算机提供的操作界面是键盘命令,因为这类操作系统采用的是联机处理方式。

在图形界面(GDI)技术、面向对象技术的推动下,现代操作系统还提供图形化的用户界面和API(用户程序编程接口),这是传统操作接口和系统功能服务界面在现代操作系统的体现,用户使用这样的界面会更为直观、方便、有效。

3.2.2 操作系统提供的用户接口

操作系统提供的用户接口如图3.2所示,它包括操作接口和系统功能服务两个方面。其中,操作接口可分为键盘命令、图形化用户界面和作业控制语言3种形式。

图像说明文字

1.操作接口

对于操作接口而言,其形式取决于操作系统的类型。具有交互操作方式的系统一般提供键盘命令或图形化用户界面;具有脱机操作方式的系统则提供对程序处理的控制语言。这是因为,前者的交互性允许用户能够人为地安排工作过程,并对系统发生的动作做出响应;而在批处理系统中,用户一旦提交了他需处理的程序,就无法控制其运行过程。因此,用户必须事先给出一系列明确的指令,指出处理的步骤,还可能需要对一些无法预测的若干事件进行周密的思考,指出当某一事件发生时应进行什么样的处理。

在分时系统和具有交互作用的系统中,操作命令最通常、最基本的形式为键盘命令。在这样的系统中,用户以联机方式上机。用户直接在控制台或终端设备上输入键盘命令,向系统提出要求,控制自己的程序有步骤地运行。现代操作系统一般还提供图形化用户界面,在这样的操作界面中,用户可以方便地借助鼠标等标记性设备,选择所需要的图标,采用点取或拖拽等方式完成自己的操作意图。

(1)键盘命令
不同的系统提供的键盘命令的数量有差异,但其功能基本上是相同的。一般终端与主机通信的过程可以分为注册、通信、注销3个步骤。
① 注册 注册的目的有两个:一是让系统验证你有无使用该系统的权限;二是让系统为你设置必要的环境。尤其是在多用户操作系统中,注册是必须的步骤。
在多用户系统中,系统为每个用户提供一个独立的环境。它要记住每一个用户的名字、注册时间,还要记住每个用户已经用了多少计算机时间,占用了多少文件,正在使用什么型号的终端等。在大多数单用户计算机系统中,不存在注册过程,因为实际地访问这个硬件就证实了你拥有使用这个系统的权力。在批处理系统中,不存在外表上的注册过程,但为了记帐和调度目的,每一个提交的作业都要加以标识。 
② 通信
当终端用户注册后,就可以通过丰富的键盘命令控制程序的运行,完成系统资源申请、从终端输入程序和数据等工作了。

属于通信这一步的键盘命令是比较丰富的,一般可分为以下几类。

  • 文件管理。这类命令用来控制终端用户的文件。例如,删去某个文件,将某个文件由显示器(或打印机)输出,改变文件的名字、使用权限等。
  • 编辑修改。这类命令用来编辑新文件或修改已有的用户文件。例如可进行删去、插入、修改等工作。
  • 编译、连接装配和运行。这类命令用来控制应用程序的处理步骤。如调出编译或连接装配程序进行编译或装配工作,以及将生成的主存映像文件装入主存启动运行。
  • 输入数据。从终端输入一批数据,并将这一批数据以文件形式放到辅存上。
  • 操作方式转换。这类命令用来转换作业的控制方式,例如,从联机工作方式转为脱机工作方式。
  • 申请资源。这类命令用于终端用户申请使用系统的资源。例如,申请使用某类外部设备若干台等。

③ 注销
当用户工作结束或暂时不使用系统时,应输入注销命令。注销就是通知系统,打算退出系统。

(2)图形化用户界面
在计算机应用迅速普及的需求下,图形化用户界面应运而生。为了使不同阶层,不同文化程度的人们都能使用计算机,必须使人机对话的界面更为方便、友好、易学,这是一个十分重要的问题。在这种需求下出现了菜单驱动方式、图符驱动方式直至视窗操作环境。现在用户十分欢迎的图形化用户界面是菜单驱动方式、图符驱动方式和面向对象技术的集成。
① 菜单驱动方式
菜单(Menu)驱动方式是面向屏幕的交互方式,它将键盘命令以屏幕方式来体现。系统将所有的命令和系统能提供的操作,用类似餐馆的菜单分类、分窗口地在屏幕上列出。用户可以根据菜单提示,像点菜一样选择某个命令或某种操作来通知系统去完成指定的工作。菜单系统的类型有多种,如下拉式菜单、上推式菜单和随机弹出式菜单。这些菜单都基于一种窗口模式。每一级菜单都是一个小小的窗口,在菜单中显示的是系统命令和控制功能。
② 图符驱动方式
图符驱动方式也是一种面向屏幕的图形菜单选择方式。图符(Icon)也称为图标,是一个很小的图形符号。它代表操作系统中的命令、系统服务、操作功能、各种资源。例如用小矩形代表文件,用小剪刀代表剪贴。所谓图形化的命令驱动方式就是当需要启动某个系统命令、操作功能或请求某个系统资源时,可以选择代表它的图符,并借助鼠标器一类的标记输入设备(也可以采用键盘),采用点击和拖拽功能,完成命令和操作的选择及执行。
图形化用户界面是良好的用户交互界面,它将菜单驱动方式、图符驱动方式、面向对象技术等集成在一起,形成一个图文并茂的视窗操作环境。Microsoft公司的Windows系统就是这种图形化用户界面的代表。

2.程序接口

操作系统和用户的第二个接口是系统功能调用,它是管理程序提供的服务界面,更确切地说,是程序设计语言中增加的操作系统提供服务的语言表示。在源程序中,除了要描述所需完成的逻辑功能外,还要请求系统资源,如请求工作区,请求建立一个新文件或请求打印输出等,这些都需要操作系统的服务支持。这种在程序一级的服务支持称为系统功能调用。

系统功能调用是针对程序设计者而提供的操作系统服务方式,在采用面向对象技术的系统中,为程序员提供的是API(应用程序编程接口)函数和系统定义的消息形式。

3.3 系统功能调用

为了实现在程序级的服务支持,操作系统提供系统功能调用,采用统一的调用方式——访问管理程序来实现对这些功能的调用。

3.3.1 系统功能调用的定义

对于用户所需要的各种功能,在操作系统设计时,就确定和编制好能实现这些功能的例行子程序,它们属于操作系统内核模块。用户程序如何调用这些例行子程序,以达到请求操作系统服务的目的呢?操作系统的例行子程序不能采用用户子程序那种方式来调用,因为用户程序运行时处于用户态,而操作系统例行子程序执行时处于管态。用户程序请求操作系统服务时,会发生处理机状态的改变,由用户态转变为管态。而应用程序调用子程序时,同处用户态,不会发生处理机状态的改变。所以,用户程序对操作系统例行子程序的调用应以一种特殊的调用方式,就是访管方式来实现。

用户所需要的功能,有些是比较复杂的,硬件不能直接提供,只能通过软件程序来实现;有些功能,硬件有相应的指令,如启动外设工作,硬件就有I/O指令。但配置了操作系统后,对系统资源的分配、控制不能由用户干预,必须由操作系统统一管理。所以,对于这样一类功能,也需有相应的控制程序来实现。

为了实现对这些事先编制好的、具有特定功能的例行子程序的调用,现代计算机系统提供自愿进管指令,其指令的一般形式为:svc n;其中,svc表示机器自愿进管指令的操作码记忆符,n为地址码。svc是supervisor call(访问管理程序)的缩写,所以svc指令又称访管指令。

当处理机执行到访管指令时就发生中断,称为访管中断(或自愿进管中断),它表示正在运行的程序对操作系统的某种需求。借助中断,机器状态由用户态转为管态,进入访管中断处理程序,经过访管中断处理程序的处理,控制会转到用户所需要的那个例行子程序。如何能使控制转到用户所需要的那个例行子程序呢?这就用到了访管指令中的地址码,用这个地址码来表示系统调用的功能号,它是操作系统提供的众多的例行子程序的编号。在访管指令中填入相应的号码,就能使控制转到特定的例行子程序去执行,实现用户当前所需要的服务。

系统功能调用是用户在程序一级请求操作系统服务的一种手段,它不是一条简单的硬指令,而是带有一定功能号的访管指令。它的功能并非由硬件直接提供,而是由操作系统中的一段程序完成的,即由软件方法实现的。

系统功能调用和访管指令是有区别又有联系的两个概念。首先,系统功能调用是操作系统提供的程序接口,是操作系统命令集中的一部分;而访管指令是一条机器指令,是裸机提供的接口。其次,系统功能调用是由软件实现的;而访管指令是通过硬件实现的。二者又是有联系的,每一个带有确定功能号的访管指令对应一条操作系统的系统功能调用,换句话说,即为一个带有一定功能号的访管指令定义了一个系统调用。可以这样说,系统调用是利用“访管指令”定义的命令。用户可以用带有不同功能号的访管指令来请求各种不同的功能。

操作系统服务例程与一般子程序的区别在于,操作系统服务例程实现的功能都是与计算机系统本身有关的,对它的调用是通过一条访管指令来实现的。不同的程序设计语言提供的操作系统服务的调用方式不同,它们有显式调用和隐式调用之分。在汇编语言中是直接使用系统调用对操作系统提出各种请求,因为在这种情况下,系统调用具有汇编指令的形式。而在高级语言中一般是隐式的调用,经过语言编译程序处理后转换成直接调用形式。

3.3.2 系统功能调用的实现

操作系统的服务是通过系统调用来实现的,系统调用提供运行程序和操作系统之间的接口。实现这种服务是由系统服务请求机构提供的,系统服务请求(System Service Request,SSR)机构本质上是一个自陷门(Trap Door)。SSR的执行通常取决于计算机的结构,它由特定的访管指令来实现对操作系统某一服务例程的调用,访管指令的执行将发生访管中断。

不同的计算机提供的系统功能调用的格式和功能号的解释都不同,但都具有以下共同的特点:①每个系统调用对应一个功能号,要调用操作系统的某一特定例程,必须在访管时给出对应的功能号;②按功能号实现调用的过程大体相同,都是由软件通过对功能号的解释分别转入到对应的例行子程序。图3.3所示为系统调用的执行过程。

图像说明文字

为了实现系统调用,操作系统设计者必须完成的工作如下。

① 编写并调试好能实现各种功能的例行子程序,如sub0、sub1、…、subi、…、subm。
② 编写并调试好访管中断处理程序,其功能是:做常规的现场保护后,取i值,然后安排一条转移指令,按A+i单元中的内容转移。
③ 构造例行子程序入口地址表。假定该表首址为A,每个例行子程序的入口地址占一个字长,将各例行子程序的入口地址#sub0,#sub1,…,#subi,…,#subm(即a0,a1,…,ai,…,am)分别送入A+0,A+1,…,A+i,…,A+m单元中。

在用户程序中,需要请求操作系统服务的地方安排一条系统调用。这样,当程序执行到这一条命令时,就会发生中断,系统由用户态转为管态,操作系统的访管中断处理程序得到控制权,它将按系统调用的功能号,借助例行子程序入口地址表转到相应的例行程序去执行,在完成了用户所需要的服务功能后,退出中断,返回到用户程序的断点继续执行。

3.3.3 应用程序的编程接口

应用程序通过操作系统提供的程序接口请求操作系统的服务、访问各类资源。应用程序发送请求,内核接收并处理请求。在任何操作系统中,系统调用是用户空间访问内核的唯一手段。

应用程序可以使用各种语言编程,若用低级语言(如汇编程序设计语言)编制,则可直接使用系统提供的系统调用,即使用显式方式调用。若使用高级语言编程,则采用隐式方式调用。这种隐式调用是由API函数和标准C库函数来提供的。

一般情况下,应用程序通过API(应用程序编程接口)来请求操作系统服务。在UNIX和Linux系统中,应用程序编程接口是基于POSIX标准的。根据POSIX标准定义的API函数与系统调用之间存在着直接的关系。Linux系统与UNIX系统一样,将系统调用作为C库的一部分来提供。C库实现了UNIX系统的主要API,包括标准C库函数和系统调用。图3.4说明了应用程序、C库和操作系统内核的关系。

图像说明文字

需要说明的是,系统调用与库函数之间是有区别的:库函数由软件开发商提供,由编译链接工具链入用户程序,库函数的执行不会引起CPU状态的变化;而系统调用的代码属于OS,系统调用代码执行时使CPU的状态由用户态变为核心态。有的库函数不涉及系统调用(如字符串操作函数stracat),有的库函数则会隐式地发出系统调用请求。我们以Linux的库函数sethostname为例来说明。

函数名称:sethostname(const char *name,size_t len);

函数功能:设置计算机的主机名;

返回值:成功为0,否则为-1;

参数:主机名name及其字符串长度。

通过将C库libc.a反汇编可以看到sethostname的代码如下:

00000000 :
0: movl %ebx, %edx #保存ebx
2: movl 0x8(%esp,1), %ecx #从栈中取参数len(主机名长度)
6: movl 0x4(%esp,1),%ebx #从栈中取参数name(主机名)
a: movl $0x4a,%eax #系统调用号为0x4a
f: int $0x80 #系统调用
11: movl $edx,%ebx
13: cmpl $0xfffff001,%eax #检查系统调用的返回值
18: jae la #出错返回
1a: _syscall_error
1e: ret

目录

同系列书

人邮微信
本地服务
人邮微信
教师服务
二维码
读者服务
读者服务
返回顶部
返回顶部