OS(二十三):接口之 系统调用
操作系统是用户与计算机硬件系统之间的接口。OS向用户提供了 用户接口 和 程序接口 两类接口。
用户接口:操作系统为用户提供的用户与操作系统的接口。
程序接口:操作系统向编程人员提供程序与操作系统的接口。
1、系统调用
程序接口是OS专门为各用户程序设置的,是用户程序获取OS服务的唯一途径。
系统调用提供了 用户程序 和 操作系统 之间的接口,应用程序通过系统调用实现与OS的通信,并可取得它的服务。
按功能可把系统调用划分为:进程控制的系统调用、文件管理的系统调用、设备管理的系统调用及进程通信的系统调用等。
1.1、系统调用的基本概念
在OS的核心中都设置了一组用于实现各种系统功能的子程序(过程),并将它们提供给应用程序调用。这些程序是OS系统程序模块的一部分,为保护操作系统程序不被用户破坏,不允许应用程序采用一般的过程调用方式来直接调用这些过程,而是向应用程序提供一系列的系统调用命令,应用程序通过系统调用区调用所需的系统过程。
1.1.1、系统态和用户态
计算机系统中,运行着两类程序:系统程序和应用程序。
为保证系统程序的安全,为计算机设置了两种状态:系统态(管态/核心态) 和 用户态 (目态)。
操作系统在系统态运行,应用程序在用户态运行。实际的运行过程中,处理机会在系统态和用户态间切换。
操作系统将CPU的指令集的分为特权指令和非特权指令两类。
1、特权指令
在系统态时运行的指令,是系统全局的指令。
2、非特权指令
在用户态时运行的指令,对内存的访问局限于用户空间。
1.1.2、系统调用
由于系统提供了保护机制,防止应用程序直接调用操作系统,但程序必须取得操作系统提供的服务。操作系统提供了系统调用,使应用程序通过系统调用,简接调用操作系统的相关过程,取得相应的服务。
系统调用在本质上是应用程序请求OS内核完成某功能时的一种过程调用,是一种特殊的过程调用:
1、运行在不同的系统状态
系统调用与一般调用最大的区别在于:调用程序是运行在用户态,被调用程序是运行在系统态。
2、状态的转换通过软中断进入
运行系统调用时,调用和被调用过程工作在不同的系统状态。不允许由调用过程直接转向被调用过程。通过软中断机制,先由用户态转为系统态,经核心分析过后,才转向相应的系统调用处理子程序。
3、返回问题
采用抢占式调度方式系统中,在被调用过程执行完后,要对系统中所有要求运行的进程做优先权分析。
4、嵌套调用
在一个被调用过程的执行期间。利用系统调用命令去调用另一个系统调用。
1.1.3、中断机制
系统调用是通过中断机制实现,并且一个操作系统的所有系统调用都通过同一个中断入口实现。
1.2、系统调用的类型
系统调用分为:进程控制、文件操纵、通信管理和系统维护。
1.2.1、进程控制类系统调用
该类系统调用主要用于对进程的控制。
1、创建和终止进程的系统调用
利用创建进程的系统调用为并发执行的各程序分别创建一个进程。
进程执行结束时,利用终止进程的系统调用结束该进程的运行。
2、获得和设置进程属性的系统调用
利用设置进程属性的系统调用,确定和重新设置进程的属性。
3、等待某事件出现的系统调用
进程在运行过程中,需要等待某事件出现后方可继续执行,利用等待的系统调用,使自己处于等待状态。
1.2.2、文件操作类系统调用
文件操作有创建、删除、打开、关闭、读/写文件等。
1.2.3、进程通信类系统调用
在OS中常采用两种进程通信方式,消息传递方式和共享存储区方式。
采用消息传递方式,通信前,须先打开一个连接,由源进程发出一条打开连接(open connection)的系统调用,而目标进程则利用接收连接(accept connection)的系统调用表示同意进行通信。源程序和目标进程之间可进行通信,利用发送消息的系统调用send message 或者用接收消息的系统调用receive message来交换信息。通信结束后,利用关闭连接(close connection)的系统调用 结束通信。
利用共享存储区方式,通信前,先利用建立共享存储区的系统调用建立一个关系存储区,在利用建立连接的系统调用将该共享存储区连接到进程自身的虚地址空间上,利用读和写共享存储区的系统调用实现相互通信。
1.3、系统调用的实现
系统调用,控制是由原来的用户态转为系统态,通过中断和陷入机制完成的。该机制包括中断和陷入硬件机构、中断与陷入处理程序两部分。
应用程序使用OS的系统调用时,产生一条相应的指令,CPU在执行这条指令时发生中断,并将有关信号送给中断和陷入硬件机构,该机构在收到信号后,启动相关的中断与陷入处理程序进行处理,实现该系统调用所需要的功能。
1.3.1、中断和陷入硬件机构
1、中断和陷入
中断:CPU对系统发生某事件时的一种响应,CPU暂停正在执行的程序,在保留现场后自动的转去执行该事件的中断处理程序;执行完后,再返回到原程序的断点处继续执行。
中断时的CPU轨迹如下:
中断可分为外中断 和 内中断。
外中断:由于外部设备事件所引起的中断,如程序出错、电源故障等;
内中断:"捕获"或"陷入",陷入是由于执行了现行指令引起的,而中断则是由于系统中某事件引起的,改时间与现行指令无关。
系统调用引起的中断属于内中断,由于系统调用引起中断的指令被称为陷入指令。
2、中断和陷入向量
中断向量:中断处理程序,处理机状态字PSW 被称为中断向量。
存放中断向量的单元被称为中断向量单元。
在进行中断处理时,只要有 中断处理程序,处理机状态字PSW 的中断向量。便可转入响应设备的中断处理程序,重新装配处理机的状态字和优先级,进行对该设备的处理。
对于陷入,也有陷入向量,根据陷入指令的陷入向量,转入实现对应的系统调用功能的子程序,即陷入程序。
所有的中断向量和陷入向量构成了中断和陷入向量表:
1.3.2、系统调用号和参数的设置
每个系统调用都有唯一的系统调用号,可直接把系统调用号放在系统调用命令(陷入指令)中;也可将系统调用装入某指定寄存器或内存单元中。
每一条系统调用含有若干个参数,在执行系统调用时,可以通过 陷入指令自带方式、直接将参数送入相应寄存器、参数表方式 ,将参数传递给陷入处理机构和系统内部的子进程。
1.3.3、系统调用的处理步骤
设置了系统调用号和参数,便可执行一条系统调用命令。
1、第一步
处理机状态由用户态转为系统态
保护被中断进程的CPU环境
将处理机状态字PSW、程序计数器PC、系统调用号、用户栈指针一级通用寄存器内存等内容,压入堆栈
将用户定义的参数传送到指定的地址保存起来
2、第二步
分析系统调用类型,转入相应的系统调用处理子程序。
在系统中配置一张系统调用入口表,表中的每个表目都对应一条系统调用,包含自带参数的数目、系统调用处理子程序入口地址等。利用系统调用号查找该表,即可找到相应 处理子程序的入口地址而转去执行它。
系统调用的功能主要是由系统调用子程序完成。
3、第三步
在系统调用处理子程序执行完后,应恢复被中断的或设置新进程的CPU现场,然后返回被中断进程或新进程,继续往下执行。
2、UNIX系统调用
UNIX系统调用根据功能可划分为 进程控制、文件草丛、进程间通信等。
2.1、进程控制
该类系统调用包括:创建进程的系统调用fork、终止进程的系统调用exit、等待子进程结束的系统调用wait等
2.1.1、创建进程(fork)
一个进程可利用fork系统调用来创建新进程,新进程作为调用者的子进程,它继承了父进程几乎所有的属性。
2.1.2、终止进程(exit)
一个进程可利用exit实现自我终止。
2.1.3、等待子进程结束(wait)
wait用于将调用者进程自身挂起,直至它的某一子进程终止为止。如此,父进程利用wait使自身的执行与子进程的终止同步。
2.1.4、执行一个文件(exec)
exec可使调用者进程的映像被一个可执行的文件覆盖,即改变调用者进程的进程映像。
2.1.5、获得进程ID
提供了一组用于获得进程标识符的系统调用。
2.1.6、进程暂停(pause)
用此系统调用将调用进程挂起,直至它收到一个信号为止。
2.2、文件操纵
文件操作的系统调用,包括创建文件、打开文件、关闭文件等。
2.2.1、创建文件(creat)
系统调用creat是根据用户提供的文件名和许可权方式,创建一个新文件后重写一个已存文件。
2.2.2、打开文件(open)
系统调用open是为了方便用户及简化系统的处理。open的功能是把有关的文件属性从磁盘拷到内存中,在用户和指名文件之间建立一条快捷的通路,并给用户的返回一个文件描述符fd。文件被打开后,用户对文件的任何操作都只须使用fd而非路径名。
2.2.3、关闭文件(close)
文件暂时不访问时,调用close将文件关闭,即断开用户程序与该文件之间已经建立的快捷通路。
2.2.4、读和写文件(read、write)
用户使用open打开指定文件,才能调用read或write对文件执行读和写操作。read、write需要用户提供三个输入参数:1、文件描述符fd;2、buf换冲区首址;3、用户要求传送的字节数。
系统调用read:从fd所指示的文件中读入n个字节的数据,将它们送至有指针buf指向的缓冲区中;
系统调用write:把n个字节数据,从指针buf指向的缓冲区中写道由fd指向的文件中。
2.3、进程通信
UNIX中提供了用于进程间通信的软件包,简称IPC,由消息机制、共享存储器和信号量机制三部分组成。
2.3.1、消息机制
进程利用消息机制进行通信时,先利用 msgget系统调用 建立一个消息队列。
若成功,返回消息队列描述符msgid,用户利用msgid访问该消息队列。
进程利用 msgsend系统调用 向用户指定的消息队列发送消息;利用 msgrcv系统调用 从指定的消息队列中接收指定类型的消息。
2.3.2、共享存储器机制
进程利用共享存储器进行通信时,先利用 shmget系统调用 建立一个共享存储区。
若成功,返回共享存储区描述符shmid。
进程建立共享存储区后,利用 shmat系统调用,将共享存储区连接到本进程的虚地址空间上;
进程回收共享存储区,利用 shmdt系统调用,拆除进程与共享存储区间的连接。
2.3.3、信号量机制
允许将一组信号量形成一个信号量级,并对这组信号施以原子操作。
2.4、被中断进程的环境保护
系统发生中断和陷入的情况,先进入trap.S程序。
2.4.1、CPU环境保护
用户程序处在用户态,且在执行系统调用命令(CHMK)前,应在用户空间提供系统调用所需的参数表,并将该参数表的地址送入R0寄存器。
在执行CHMK后,处理机将由用户态转为核心态,由硬件自动的将处理机状态长字(PSL)、程序计数器(PC)和代码操作数压入用户核心栈,继而从中断和陷入向量表中取出trap,S的入口地址,然后转入中断和陷入总控程序trap.S中执行。
2.4.2、AP和FP指针
系统调用参数表指针AP,用于指示正在执行的系统调用所需参数表的地址,通常把该地放在某个寄存器中,还需设置一个调用栈帧指针。
调用栈帧:某个系统调用需要保护而被压入用户核心栈的所有数据项。
站帧指针FP:用于指示本次系统调用所保存的数据项,每当出现新的系统调用时,须将AP和FP压入栈中。
2.4.3、系统调用陷入后需处理的公共问题
trap.C程序是一个处理各种陷入情况的C语言文件,trap.C用于处理在中断和陷入发生后需要处理的若干公共问题。
若因系统调用而进入trap.C时,索要进行的处理将包括:确定系统调用号、实现参数传送、转入相应的系统调用处理子程序。
由相应的系统调用处理子程序返回到trap.C后,重新计算进程的优先级,对收到信号进程处理等。
1、确定系统调用号
在中断和陷入后,先经硬件陷入机构处理,再进入trap.S,然后在调用trap.C继续处理。
trap(usp, type, code, PC, PSL)
PSL为陷入时处理机状态字长,PC为程序计数器,code为代码操作数,type为陷入类型号,usp为用户栈指针。
通常,系统调用号包含在代码操作数中,可利用code确定系统调用号i,
i = code & 0377
若 0 < i < 64,i 标识系统调用号,根据系统调用号i 和 系统调用定义表,转向处理子程序;
若 i= 0,表示系统调用号并未包含在代码操作数中,此时采用间接参数方式,利用间接参数指针找到系统调用号。
2、参数传送
参数传送是指由trqap.C程序将系统调用参数表中的内容,从用户区传送到User结构的U.U-arg中,供系统调用处理程序使用。
3、利用系统调用定义表转入相应的处理程序
为使不同的系统调用能方便的转入相应的处理子程序,将各处理子程序的入口地址放入了系统调用定义表Sysent[]中。该表实际上是一个结构数组,每个结构中包含三个元素,第一个元素是相应系统调用所需参数的个数;第二个元素是系统调用经寄存器传送的参数个数;第三个元素是相应系统调用处理子程序的入口地址。
4、系统调用返回前的公共处理
进程调用的众泰依据是进程的动态优先级,每当执行了系统调用命令,并由系统调用处理子程序返回到trap.C后,将重新计算该进程的优先级,另外,在系统调用执行过程中,若发生了错误使进程无法继续运行时,系统会设置再调度标志。