系统调用(System Call)
首先让我们来看看《维基百科》中对系统调用的解释:
系统调用,又名系统呼叫,是指运行在使用者空间的程序向操作系统内核请求更高权限的服务。
来让我举个例子,看看系统调用和我们的紧密联系。假使现在你要编一个从一个文件读取信息并复制到另一个文件的程序,首先你必须要知道这两个文件的名称从而准确定位,一种比较常见的形式就是程序对用户有所提示,然后得到两个文件名。对于GUI(图形用户界面),这就需要产生很多的系统调用,程序的提示显示在屏幕上就是一种系统调用,当然,如果你有鼠标的话,你完全可以通过它来选择源文件而不必输入名字,显然,伴随着这一过程的仍然是I/O系统调用。得到了两个文件名之后,接下来就是打开输入文件(系统调用),当然可能会遇到错误,当程序准备打开输入文件时,发现该文件不存在或者因受保护而无法打开,那么就会返回错误信息输出到屏幕(系统调用),从而终止。如果正常打开输入文件,那么必须要创建一个输出文件,若发现输出文件存在,那么可能需要删除现有的文件,创建一个新的文件(一个系统调用)。如果是交互式系统的话,可能会问用户是否要替换现有文件或者终止。接下来就是进入了循环,从输入文件中读,到另一个文件中写,这一过程也可能会返回一些错误信息,比如读的时候发生奇偶校验误差,写的过程中发现存储空间不够等,都会导致终止。最后,在整个文件复制完成之后,程序需要关闭两个文件(系统调用),在终端上显示提示消息(一个系统调用),最后正常结束。
从上面的例子我们可以知道,这只是一个不算复杂的程序,但其中我们甚至可能用到了上千个系统调用,由此可见,系统调用与我们是息息相关的,但是对于大多数程序员而言,他们是看不到这些细节的,一般的程序开发人员都是根据程序接口设计程序而很少关心这些较为底层的东西。
一般会把系统调用划分为五种类型:【进程控制】、【文件管理】(例子中有出现)、【设备管理】、【通信】、【信息管理】
下面让我们一一来看看它们的一些特性:
进程控制
进程控制的主要功能是对进程的创建和删除以及进程间状态的转换。如果创建一个新作业或者进程,那么我们能控制它们的运行和终止,能设置它们的属性,包括作业的优先级,最大等待时间等,如果发现其运行不正常或者不再需要它了,我们也可以终止。创建了一个新的进程之后,可能需要一段时间来等待其完成,期间也有可能需要等待其他某个事件的出现,当事件出现后,才能完成。下面是一个C程序库调用:
在这一过程中,C程序调用了printf()语句,C程序库拦截这个调用来调用一个必要的系统调用[write()系统调用],并把write()的调用值返回给用户。
文件管理
让我们看看一些常用的文件系统调用。首先你需要创建和删除文件,创建文件当然需要文件名了,这给用户的提示就需要一个系统调用,然后你还需要设置文件的属性什么的,这也需要系统调用。一旦创建文件成功,我们就需要打开它并使用它,这一过程有读、写、重定位,操作结束后关闭它。如果你采用目录结构来进行文件管理,那么目录也需要同样的操作。无论是文件还是目录,都需要设置其属性,文件的属性包括文件名、文件类型、保护模式、创建时间、最后一次访问时间等。至少需要两个系统调用(读取文件属性和设置文件属性)来完成这个功能。如果需要完成文件的复制和移动,就需要更多的系统调用。
设备管理
一个程序的执行过程中,肯定会用到各种各样的资源,包括内存、磁盘、文件的访问等等,如果有足够的资源,那么程序就会正常的运行,否则的话程序必须等待足够多的资源。操作系统的某些资源可以当做设备来看待,比如有些是物理设备(磁盘),而另外也有一些虚拟设备(文件)。在使用完设备之后,用户需要释放它,这一过程类似于文件管理里边的open和close的系统调用。事实上,我们在对待文件和设备上,可以采用同一套系统调用。
通信
通信分为两种,一种是消息传递模式,另一种是共享内存模式。
对于消息传递,通信进程通常通过彼此间交换消息来交换信息,它们可能是同一个CPU上的进程,也可能是通过网络连接的不同计算机上的的进程。不管是前者还是后者,都必须要知道另一方通信实体的名称,从而准确连接。前者比较容易,只需知道对方的进程名称就OK,如果是后者该怎么办呢,我们知道每台计算机都有不同的主机名,而在网络上的主机一般都有自己的网络标识,如IP,它们通常会转化成标志符以便被系统调用。系统调用get hostid和get processid用于这一转换,这些标识符再传递给文件里的 通用的open connection和close connection系统调用。接收方通常通过accept connection调用来允许通信,在接受方后台有一些特殊的程序用于连接,它们执行wait for connection,当有连接的时候就会被唤醒。通信源一般称为客户机,接受方则是服务器。通过read message和write message 系统调用来交换信息。
来看看共享内存模式,进程通常可以通过shared memory creat和shared memory attach系统调用来获得其它进程所拥有的内存区域访问权。我们知道操作系统是会限制一个进程访问另一个进程的的内存的(可能会产生未知名的破坏),而共享内存模式里则会要求两个或者多个进程取消这一限制,从而可以通过读写公共区域来交换信息。
信息管理
很多的系统调用都是用于用户和系统间传递消息的。如返回当前的日期和时间、当前用户数、操作系统信息、内存的占有率等等。操作系统也负责维护进程的信息,有些系统调用可以访问这些信息,也有的系统调用用于设置进程信息的。