原创 什么是系统调用

2020-7-18 14:29 1175 7 7 分类: 软件与OS

 系统调用发生在用户进程(比如emacs)通过调用特殊函数(例如open)以请求内核提供服务的时候。在这里,用户进程被暂时挂起。内核检验用户请求,尝试执行,并把结果反馈给用户进程,接着用户进程重新启动,随后我们就将详细讨论这种机制。

系统调用负责保护对内核所管理的资源的访问,系统调用中的几个大类主要有:处理I/O请求(openclosereadwritepoll等等),进程(forkexecvekill,等等),时间(timesettimeofday等等)以及内存(mmapbrk,等等)的系统调用。几乎所有的系统调用都可以归入这几类中。

然而,从根本上来说,系统调用可能和它表面上有所不同。首先,在Linux中,C库中对于一些系统调用的实现是建立在其它系统调用的基础之上的。例如,waitpid是通过简单调用wait4实现的,但是它们两个都是作为独立的系统调用说明的。其它的传统系统调用,如sigmaskftime是由C库而不是由Linux内核本身实现的;即使不是全部,至少大部分是如此。

当然,从技巧的一面来看这是无害的——从应用程序的观点来看,系统调用就和其它的函数调用一样。只要结果符合预计的情况,应用程序就不能确定是否真正使用到了内核。(这种处理方式还有一个潜在的优点:用户可以直接触发的内核代码越少,出现安全漏洞的机会也就越少。)但是,由于使用这种技巧所引起的困扰将会使我们的讨论更为困难。实际上,系统调用这一术语通常被演讲者用来说明在第一个Unix版本中的任何对系统的调用。但是在本章中我们只对“真正”的系统调用感兴趣——真正的系统调用至少包括用户进程对部分内核代码的调用。

系统调用必须返回int的值,并且也只能返回int的值。为了方便起见,返回值如果为零或者为正,就说明调用成功;为负则说明发生了错误。就像老练的C程序员所知道的一样,当标准C库中的函数发生错误时会通过设置全局整型变量errno指明发生错误的属性,系统调用的原理和它相同。然而,仅仅研究内核源程序代码并不能够获得这种系统调用方式的全部意义。如果发生了错误,系统调用简单返回自己所期望的负数错误号,其余部分则由标准C库实现。(正常情况下,用户代码并不直接调用内核系统函数,而是要通过标准C库中专门负责翻译的一个小层次(thin layer)实现。)我们随便举一个例子,27825行(sys_nanosleep的一部分)返回-EINVAL指明所提供的值越界了。标准C库中实际处理sys_nanosleep的代码会注意到返回的负值,从而设置errnoEINVAL,并且自己返回-1给原始的调用者。

在最近的内核版本中,系统调用返回负值偶尔也不一定表示错误了。在目前的几个系统调用中(例如lseek),即使结果正确也会返回一个很大的负值。最近,错误返回值是在-1-4095范围之内。现在,标准C库实现能够以更加成熟和高级的方式解释系统调用的返回值;当返回值为负时,内核本身就不用再做任何特殊的处理了。
PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
7
关闭 站长推荐上一条 /3 下一条