程序接口是OS专门为用户程序设置的,也是用户程序取得OS服务的唯一途径。程序接口通常是由各种类型的系统调用所组成的,换而言之,系统调用提供了用户程序和操作系统之间的接口,应用程序通过系统调用实现其与OS的通信,并可取得它的服务。系统调用不仅可供所有的应用程序使用,而且也可供OS自身的其他部分,尤其是命令处理程序使用。在每个系统中,通常都有几十条甚至上百条的系统调用,并可根据其功能把它们划分成若干类。例如,有用于进程控制(类)的系统调用和用于文件管理(类)、设备管理(类)及进程通信等类的系统调用。
由于系统调用是OS系统本身程序模块中的一部分,为了保护操作系统程序不被用户程序破坏,所以不允许应用程序采用一般的过程调用方式来直接调用这些过程,而是向应用程序提供了一系列的系统调用命令,让应用程序通过系统调用去调用所需的系统过程。
2.2.1 系统态和用户态
在计算机系统中,通常运行着两类程序:系统程序和应用程序,为了保证系统程序不被应用程序有意或无意地破坏,为计算机设置了两种状态:系统态(也称管态或核心态)和用户态(也称目态)。操作系统在系统态运行,而应用程序只能在用户态运行。在实际运行过程中,处理机会在系统态和用户态间切换。相应地,现代多数操作系统将CPU的指令集分为特权指令和非特权指令两类。
(1)特权指令。所谓特权指令,就是在系统态时运行的指令,是关系到系统全局的指令。其对内存空间的访问范围基本不受限制,不仅能访问用户存储空间,也能访问系统存储空间,如启动各种外部设备、设置系统时钟时间、关中断、清主存、修改存储器管理寄存器、执行停机指令、转换执行状态等。特权指令只允许操作系统使用,不允许应用程序使用,否则会引起系统混乱。
(2)非特权指令。非特权指令是在用户态时运行的指令。一般应用程序所使用的都是非特权指令,它只能完成一般性的操作和任务,不能对系统中的硬件和软件直接进行访问,其对内存的访问范围也局限于用户空间。这样,可以防止应用程序的运行异常对系统造成的破坏。
2.2.2 系统调用
当应用程序中需要操作系统提供服务时系统会发生状态转换,如请求I/O资源或执行I/O操作时,应用程序必须使用系统调用命令,操作系统捕获到该命令后,便将CPU的状态从用户态转换到系统态,然后执行操作系统中相应的子程序(例程),完成所需的功能。执行完成后,系统又将CPU状态从系统态转换到用户态,再继续执行应用程序。可见,系统调用在本质上是应用程序请求OS内核完成某功能时的一种过程调用,但它是一种特殊的过程调用,它与一般的过程调用有下述几方面的明显差别:
(1)运行在不同的系统状态。一般的过程调用,其调用程序和被调用程序都运行在相同的状态——系统态或用户态;而系统调用与一般调用的最大区别就在于:调用程序是运行在用户态,被调用程序则运行在系统态。
(2)状态的转换通过软中断进入。由于一般的过程调用并不涉及系统状态的转换,可直接由调用过程转向被调用过程。但在运行系统调用时,由于调用和被调用过程是工作在不同的系统状态,因而不允许由调用过程直接转向被调用过程。通常都是通过软中断机制,先由用户态转换为系统态,经核心分析后,才能转向相应的系统调用处理子程序。
(3)返回问题。在采用了抢占式(剥夺)调度方式的系统中,在被调用过程执行完后,要对系统中所有要求运行的进程做优先权分析。当调用进程仍具有最高优先级时,才返回调用进程继续执行;否则,将引起重新调度,以便让优先权最高的进程优先执行。此时,将把调用进程放入就绪队列。
(4)嵌套调用。与一般过程一样,系统调用也可以嵌套进行,即在一个被调用过程的执行期间,还可以利用系统调用命令去调用另一个系统。当然,每个系统对嵌套调用的深度都有一定的限制,例如最大深度为6。但一般的过程对嵌套的深度则没有限制。
操作系统提供的系统调用很多,从功能上大致可分成六类:
(1)进程和作业管理。终止或异常终止进程、装入和执行进程、创建和撤销进程、获取和设置进程属性。
(2)文件操作。建立文件、删除文件、打开文件、关闭文件、读写文件、获得和设置文件属性。
(3)设备管理。申请设备、释放设备、设备I/O和重定向、获得和设置设备属性、逻辑上连接和释放设备。
(4)内存管理。申请内存和释放内存。(www.xing528.com)
(5)信息维护。获取和设置日期及时间、获得和设置系统数据。
(6)通信。建立和断开通信连接、发送和接收消息、传送状态信息、连接和断开远程设备。
2.2.3 中断机制
系统调用是通过中断机制实现的,并且一个操作系统的所有系统调用都通过同一个中断入口来实现。如MS-DOS提供了INT 21H,应用程序通过该中断获取操作系统的服务。对于拥有保护机制的操作系统,中断机制本身也是受保护的,在IBM PC上,Intel提供了多达255个中断号,但只有授权给应用程序保护等级的中断号,才可以被应用程序调用。对于未被授权的中断号,如果应用程序进行调用,同样会引起保护异常,而导致自己被操作系统停止。如Linux仅仅给应用程序授权了4个中断号:3、4、5以及80 h,前三个中断号是提供给应用程序调试所使用的,而80 h正是系统调用的中断号。
2.2.4 系统调用的实现
每个操作系统都提供几十到几百条系统调用。在操作系统中,实现系统调用功能的机制称陷入或异常处理机制,由于系统调用而引起处理器中断的机器指令称访管指令(supervisor)、陷入指令(trap)或异常中断指令(interrupt)。在操作系统中,每个系统调用都事先规定了编号,称功能号,在访管或陷入指令中必须指明对应系统调用的功能号,在大多数情况下,还附带有传递给内部处理程序的参数。
中断是指CPU对系统发生某事件时的一种响应:CPU暂停正在执行的程序,在保留现场后自动地转去执行该事件的中断处理程序;执行完后,再返回原程序的断点处继续执行。还可进一步把中断分为外中断和内中断。所谓外中断,是指由于外部设备事件所引起的中断,如通常的磁盘中断、打印机中断等;内中断(trap)则是指由于CPU内部事件所引起的中断,如程序出错(非法指令、地址越界)、电源故障等。内中断也被译为“捕获”或“陷入”。通常,陷入是由于执行了现行指令所引起的;而中断则是由于系统中某事件引起的,该事件与现行指令无关。由于系统调用引起的中断属于内中断,因此把由于系统调用引起中断的指令称为陷入指令。
系统调用的实现有以下几点:①编写系统调用处理程序;②设计一张系统调用入口地址表,每个入口地址都指向一个系统调用的处理程序,有的系统还包含系统调用自带参数的个数;③陷入处理机制,需要开辟现场保护区,以保存发生系统调用时的处理器现场。图2-1所示是系统调用的处理过程。参数传递是系统调用中应处理好的问题,不同的系统调用需要传递给系统调用处理程序不同的参数;反之,系统调用执行的结果也要以参数形式返回给用户程序。实现用户程序和系统调用之间的参数传递可采用以下方法:①访管指令或陷入指令自带参数,可以规定指令之后的若干单元存放的是参数,这称为直接参数;或者在指令之后紧靠的单元中存放参数的地址,这称为间接参数,由间接地址再指出参数的存放区。②通过CPU的通用寄存器传递参数,这种方法不宜传递大量参数。改进的方法是:在内存的一个区或表中存放参数,其首地址送入寄存器,实现参数传递。③在内存中开辟专用堆栈区域传递参数。
图2-1 陷入机构和系统调用处理过程
2.2.5 POSIX标准
目前许多操作系统都提供了前面所介绍的各种类型的系统调用,实现的功能也相类似,但在实现的细节和形式方面却相差很大,这种差异给实现应用程序与操作系统平台的无关性带来了很大的困难。为解决这一问题,国际标准化组织(ISO)给出了有关系统调用的国际标准POSIX1003.1(portable operating system IX),也称为“基于UNIX的可移植操作系统接口”。
POSIX定义了标准应用程序接口,用于保证编制的应用程序可以在源代码一级上在多种操作系统上移植运行。只有符合这一标准的应用程序,才有可能完全兼容多种操作系统,即在多种操作系统下都能够运行。POSIX标准定义了一组过程,这组过程是构造系统调用所必需的。通过调用这些过程所提供的服务,确定了一系列系统调用的功能。一般而言,在POSIX标准中,大多数的系统调用是一个系统调用直接映射一个过程,但也有一个系统调用对应若干个过程的情形,如一个系统调用所需要的过程是其他系统调用的组合或变形时,则往往会对应多个过程。
需要明确的是,POSIX标准所定义的一组过程虽然指定了系统调用的功能,但并没有明确规定系统调用是以什么形式实现的,是库函数还是其他形式。如早期操作系统的系统调用使用汇编语言编写,这时的系统调用可看作扩展的机器指令,因而,能在汇编语言编程中直接使用。而在一些高级语言或C语言中,尤其是最新推出的一些操作系统,如UNIX新版本、Linux、Windows和OS/2等,其系统调用干脆用C语言编写,并以库函数形式提供,所以在用C语言编制的应用程序中,可直接通过使用对应的库函数来使用系统调用,库函数的目的是隐藏访管指令的细节,使系统调用更像过程调用。但一般而言,库函数属于用户程序而非系统调用程序。UNIX/Linux的系统程序、库函数、系统调用的层次关系如图2-2所示。
图2 2 UNIX/Linux系统程序、库函数、系统调用的层次关系
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。