系统调用

处理器(CPU)=运算器+控制器+寄存器+高速缓存

系统调用的基本概念

通常,在 OS 的核心中都设置了一组用于实现各种系统功能的子程序(过程),并将它们提供给应用程序调用。

系统态和用户态

在计算机系统中,通常运行着两类程序:系统程序和应用程序,为了保证系统程序不被应用程序有意或无意地破坏,为计算机设置了两种状态:

  • 系统态(也称为管态或核心态),操作系统在系统态运行
  • 用户态(也称为目态),应用程序只能在用户态运行。

在实际运行过程中,处理机会在系统态和用户态间切换。相应地,现代多数操作系统将 CPU 的指令集分为特权指令和非特权指令两类。

(1) 特权指令——在系统态时运行的指令

  • 对内存空间的访问范围基本不受限制,不仅能访问用户存储空间,也能访问系统存储空间,
  • 特权指令只允许操作系统使用,不允许应用程序使用,否则会引起系统混乱。

(2) 非特权指令——在用户态时运行的指令

一般应用程序所使用的都是非特权指令,它只能完成一般性的操作和任务,不能对系统中的硬件和软件直接进行访问,其对内存的访问范围也局限于用户空间

系统调用

如上所述,一方面由于系统提供了保护机制,防止应用程序直接调用操作系统的过程,从而避免了系统的不安全性。但另一方面,应用程序又必须取得操作系统所提供的服务,否则,应用程序几乎无法作任何有价值的事情,甚至无法运行。为此,在操作系统中提供了系统调用,使应用程序可以通过系统调用的方法,间接调用操作系统的相关过程,取得相应的服务。

当应用程序中需要操作系统提供服务时,如请求 I/O 资源或执行 I/O 操作,应用程序必须使用系统调用命令。由操作系统捕获到该命令后,便将 CPU 的状态从用户态转换到系统态,然后执行操作系统中相应的子程序(例程),完成所需的功能。执行完成后,系统又将CPU 状态从系统态转换到用户态,再继续执行应用程序。

系统调用和一般调用的区别:

(1) 运行在不同的系统状态——调用程序是运行在用户态,而被调用程序是运行在系统态。

(2) 状态的转换通过软中断进入

  • 一般的过程调用并不涉及到系统状态的转换,可直接由调用过程转向被调用过程。
  • 系统调用不允许由调用过程直接转向被调用过程。

通常都是通过软中断机制,先由用户态转换为系统态,经核心分析后,才能转向相应的系统调用处理子程序。

(3) 返回问题。

在采用了抢占式(剥夺)调度方式的系统中,在被调用过程执行完后,要对系统中所有要求运行的进程做优先权分析。当调用进程仍具有最高优先级时,才返回到调用进程继续执行;否则,将引起重新调度,以便让优先权最高的进程优先执行。此时,将把调用进程放入就绪队列。

(4) 嵌套调用。

像一般过程一样,系统调用也可以嵌套进行,即在一个被调用过程的执行期间,还可以利用系统调用命令去调用另一个系统调用。当然,每个系统对嵌套调用的深度都有一定的限制,例如最大深度为 6。

系统调用插图1

中断机制

系统调用是通过中断机制实现的,并且一个操作系统的所有系统调用都通过同一个中断入口来实现。对于拥有保护机制的操作系统来说,中断机制本身也是受保护的,

系统调用的类型

对于一般通用的 OS 而言,可将其所提供的系统调用分为:进程控制、文件操纵、通信管理和系统维护等几大类。

进程控制类系统调用

这类系统调用主要用于对进程的控制,如创建一个新的进程和终止一个进程的运行,获得和设置进程属性等。

(1) 创建和终止进程的系统调用

在多道程序环境下,为使多道程序能并发执行,必须先利用创建进程的系统调用来为欲参加并发执行的各程序分别创建一个进程。当进程已经执行结束时、 或因发生异常情况而不能继续执行时,可利用终止进程的系统调用来结束该进程的运行。

(2) 获得和设置进程属性的系统调用

当我们创建了一个(些)新进程后,为了能控制它(们)的运行,应当能了解、 确定和重新设置它(们)的属性。这些属性包括: 进程标识符、进程优先级、最大允许执行时间等。此时,我们可利用获得进程属性的系统调用,来了解某进程的属性,利用设置进程属性的系统调用,来确定和重新设置进程的属性。

(3) 等待某事件出现的系统调用

进程在运行过程中,有时需要等待某事件(条件)出现后方可继续执行。例如,一进程在创建了一个(些)新进程后,需要等待它(们)运行结束后,才能继续执行,此时可利用等待子进程结束的系统调用进行等待;

文件操纵类系统调用

对文件进行操纵的系统调用数量较多,有创建文件、删除文件、打开文件、关闭文件、读文件、写文件、建立目录、移动文件的读/写指针、改变文件的属性等。

(1) 创建和删除文件

当用户需要在系统中存放程序或数据时,可利用创建文件的系统调用 creat,由系统根据用户提供的文件名和存取方式来创建一个新文件;当用户已不再需要某文件时,可利用删除文件的系统调用 unlink 将指名文件删除。

(2) 打开和关闭文件

用户在第一次访问某个文件之前,应先利用打开文件的系统调用 open,将指名文件打开,即系统将在用户(程序)与该文件之间建立一条快捷通路。在文件被打开后,系统将给用户返回一个该文件的句柄或描述符;当用户不再访问某文件时,又可利用关闭文件的系统调用 close,将此文件关闭,即断开该用户程序与该文件之间的快捷通路。

(3) 读和写文件

用户可利用读系统调用 read,从已打开的文件中读出给定数目的字符,并送至指定的缓冲区中;同样,用户也可利用写系统调用 write,从指定的缓冲区中将给定数目的字符写入指定文件中。read 和 write 两个系统调用是文件操纵类系统调用中使用最频繁的。

进程通信类系统调用

在 OS 中经常采用两种进程通信方式,即消息传递方式和共享存储区方式。

当系统中采用消息传递方式时

  1. 先打开一个连接(由源进程发出一条打开连接的系统调用 open connection,目标进程则应利用接受连接的系统调用 accept connection
  2. 可以利用发送消息的系统调用 send message 或者用接收消息的系统调用 receive message 来交换信息。
  3. 通信结束后,还须再利用关闭连接的系统调用 close connection 结束通信。

用户在利用共享存储区进行通信

  1. 先利用建立共享存储区的系统调用来建立一个共享存储区
  2. 再利用建立连接的系统调用将该共享存储区连接到进程自身的虚地址空间上
  3. 然后便可利用读和写共享存储区的系统调用实现相互通信。

除上述的三类外,常用的系统调用还包括设备管理类系统调用和信息维护类系统调用,

系统调用的实现

系统调用的实现与一般过程调用的实现相比,两者间有很大差异。对于系统调用,控制是由原来的用户态转换为系统态,这是借助于中断和陷入机制来完成的,在该机制中包括中断和陷入硬件机构及中断与陷入处理程序两部分。当应用程序使用 OS 的系统调用时,产生一条相应的指令,CPU 在执行这条指令时发生中断,并将有关信号送给中断和陷入硬件机构,该机构收到信号后,启动相关的中断与陷入处理程序进行处理,实现该系统调用所需要的功能。

中断和陷入硬件机构

(1) 中断和陷入的概念(面试考点——中断与异常的区别)

中断是指 CPU 对系统发生某事件时的这样一种响应: CPU 暂停正在执行的程序,在保留现场后自动地转去执行该事件的中断处理程序;执行完后,再返回到原程序的断点处继续执行。

下图 表示中断时 CPU 的活动轨迹。还可进一步把中断分为外中断和内中断。

  • 外中断——是指由于外部设备事件所引起的中断,如通常的磁盘中断、打印机中断等;
  • 内中断——是指由于 CPU 内部事件所引起的中断,如程序出错(非法指令、地址越界)。内中断(trap)也被译为捕获或陷入。

通常,陷入是由于执行了现行指令所引起的;而中断则是由于系统中某事件引起的,该事件与现行指令无关。由于系统调用引起的中断属于内中断,因此把由于系统调用引起中断的指令称为陷入指令。

系统调用插图3

(2) 中断和陷入向量(百度面试考过中断向量)

  • 针对不同的设备编制不同的中断处理程序,并把该程序的入口地址放在某特定的内存单元中。
  • 不同的设备也对应着不同的处理机状态字PSW,且把它放在与中断处理程序入口指针相邻接的特定单元中。

在进行中断处理时,只要有了这样两个字,便可转入相应设备的中断处理程序,重新装配处理机的状态字和优先级,进行对该设备的处理。因此,我们把这两个字称为中断向量。相应地,把存放这两个字的单元称为中断向量单元。

类似地,对于陷入,也有陷入向量,不同的系统调用对应不同的陷入向量,在进行陷入处理时,根据陷入指令中的陷入向量,转入实现相应的系统调用功能的子程序,即陷入处理程序。由所有的中断向量和陷入向量构成了中断和陷入向量表,如图所示。

系统调用插图5

UNIX 系统调用

UNIX 系统调用的类型进程控制

该类系统调用包括:创建进程的系统调用 fork、终止进程的系统调用 exit、等待子进程结束的系统调用 wait 等十多条。

(1) 创建进程(fork)。

一个进程可以利用 fork 系统调用来创建一个新进程。新进程是作为调用者的子进程,它继承了其父进程的环境、 已打开的所有文件、根目录和当前目录等,即它继承了父进程几乎所有的属性,并具有与其父进程基本上相同的进程映像。

(2) 终止进程(exit)。

一个进程可以利用 exit 实现自我终止。通常,在父进程创建子进程时,便在子进程的末尾安排一条 exit 系统调用。这样,子进程在完成规定的任务后,便可进行自我终止。子进程终止后,留下一记账信息 status,其中包含了子进程运行时记录下来的各种统计信息。

(3) 等待子进程结束(wait)。

wait 用于将调用者进程自身挂起,直至它的某一子进程终止为止。这样,父进程可以利用 wait 使自身的执行与子进程的终止同步。

(4) 执行一个文件(exec)。

exec 可使调用者进程的进程映像(包括用户程序和数据等)被一个可执行的文件覆盖,此即改变调用者进程的进程映像。该系统调用是 UNIX 系统中最复杂的系统调用之一。

(5) 获得进程 ID。

UNIX 系统提供了一组用于获得进程标识符的系统调用,比如,可利用 getpid 系统调用来获得调用进程的标识符,利用 getpgrp 系统调用来获得调用进程的进程组 ID,以及利用 getppid 系统调用来获得调用进程的父进程 ID 等。

(6) 获得用户 ID。

UNIX 系统提供了一组用于获得用户 ID 的系统调用,如 getuid 可用于获得真正的用户 ID,geteuid 用于获得有效用户 ID,getgid 用于获得真正用户组 ID 等。

(7) 进程暂停(pause)。

可用此系统调用将调用进程挂起,直至它收到一个信号为止

文件操纵

用于对文件进行操纵的系统调用是数量最多的一类系统调用,其中包括创建文件、打开文件、关闭文件、读文件及写文件等二十多条。

(1) 创建文件(creat)。

系统调用 creat 的功能是根据用户提供的文件名和许可权方式,来创建一个新文件或重写一个已存文件。如果系统中不存在指名文件,核心便以给定的文件名和许可权方式来创建一个新文件;如果系统中已有同名文件,核心便释放其已有的数据块。创建后的文件随即被打开,并返回其文件描述符 fd。若 creat 执行失败,便返回-1。

(2) 打开文件(open)。

open 的功能是把有关的文件属性从磁盘拷贝到内存中,以及在用户和指名文件之间建立一条快捷的通路,并给用户返回一个文件描述符 fd。文件被打开后,用户对文件的任何操作都只须使用 fd 而非路径名。

(3) 关闭文件(close)。

在 UNIX 系统中,由于允许一个文件被多个进程所共享,故只有在无其他任何进程需要此文件时,才能真正关闭该文件。

(4) 读和写文件 read 和 write。

仅当用户利用 open 打开指定文件后,方可调用 read 或write 对文件执行读或写操作。两个系统调用都要求用户提供三个输入参数:

  • ① 文件描述符fd。
  • ② buf 缓冲区首址。对读而言,这是用户所要求的信息传送的目标地址;对写而言,这则是信息传送的源地址。
  • ③ 用户要求传送的字节数 n byte。

系统调用 read 的功能是试图从 fd 所指示的文件中去读入 n byte 个字节的数据,并将它们送至由指针 buf 所指示的缓冲区中;系统调用 write 的功能是试图把 n byte 个字节数据,从指针 buf 所指示的缓冲区中写到由 fd 所指向的文件中。

(5) 连接和去连接(link 和 unlink)。

为了实现文件共享,必须记住所有共享该文件的用户数目。为此,在该文件的索引结点中设置了一个连接计数 link。每当有一用户要共享某文件时,须利用系统调用 link 来建立该用户(进程)与此文件之间的连接,并对i.link做加 1操作。当用户不再使用此文件时,应利用系统调用 unlink 去断开此连接,亦即做i.link的减1 操作。当i.link减 1 后结果为 0 时,表示已无用户需要此文件,此时才能将该文件从文件系统中删除。故在 UNIX 系统中并无一条删除文件的系统调用。

进程间的通信

为了实现进程间的通信,在 UNIX 系统中提供了一个用于进程间通信的软件包,简称IPC。它由消息机制、共享存储器机制和信号量机制三部分组成。在每一种通信机制中,都提供了相应的系统调用供用户程序进行进程间的同步与通信之用。

(1) 消息机制。

用户(进程)在利用消息机制进行通信时,必须先利用 msgget 系统调用来建立一个消息队列。若成功,便返回消息队列描述符 msgid,以后用户便可利用 msgid 去访问该消息队列。用户(进程)可利用发送消息的系统调用 msgsend 向用户指定的消息队列发送消息;利用 msgrcv 系统调用从指定的消息队列中接收指定类型的消息。

(2) 共享存储器机制。

当用户(进程)要利用共享存储器机制进行通信时,必须先利用shmget 系统调用来建立一个共享存储区,若成功,便返回该共享存储区描述符 shmid。以后,用户便可利用 shmid 去访问该共享存储区。进程在建立了共享存储区之后,还必须再利用shmat 将该共享存储区连接到本进程的虚地址空间上。以后,在进程之间便可利用该共享存储区进行通信。当进程不再需要该共享存储区时,可利用 shmdt 系统调用来拆除进程与共享存储区间的连接。

(3) 信号量机制。

在 UNIX 系统中所采用的信号量机制,允许将一组信号量形成一个信号量集,并对这组信号量施以原子操作。

信息维护

在 UNIX 系统中,设置了许多条用于系统维护的系统调用。

(1) 设置和获得时间。

超级用户可利用设置时间的系统调用(stime),来设置系统的日期和时间。如果调用进程并非超级用户,则 stime 失败。一般用户可利用获得时间的系统调用time 来获得当前的日期和时间。

(2) 获得进程和子进程时间(times)。

利用该系统调用可获得进程及其子进程所使用的CPU 时间,其中包括调用进程在用户空间执行指令所花费的时间,系统为调用进程所花费的 CPU 时间、子进程在用户空间所用的 CPU 时间、系统为各子进程所花费的 CPU 时间等,并可将这些时间填写到一个指定的缓冲区。

(3) 设置文件访问和修改时间(utime)。

该系统调用用于设置指名文件被访问和修改的时间。如果该系统调用的参数 times 为 NULL 时,文件主和对该文件具有写权限的用户,可将对该文件的访问和修改时间设置为当前时间;如果 times 不为 NULL,则把 times 解释为指向 utim buf 结构的指针,此时,文件主和超级用户能将访问时间和修改时间置入 utim buf结构中。

(4) 获得当前 UNIX 系统的名称(uname)。

利用该系统调用可将有关 UNIX 系统的信息存储在 utsname 结构中。 这些信息包括 UNIX 系统名称的字符串、系统在网络中的名称、 硬件的标准名称等。

系统调用插图7

原创文章 系统调用,版权所有
如若转载,请注明出处:https://www.itxiaozhan.cn/20222170.html

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注