首页 > 代码库 > linux内核--系统调用
linux内核--系统调用
为了和用户空间上运行的进程进行交互,内核提供了一组接口。透过该接口,应用程序可以访问硬件设备和其他操作系统资源。这组接口在应用程序和内核之间扮演了使者的角色,应用程序发送各种请求,而内核负责满足这些请求。系统调用在用户空间和硬件设备之间添加了一个中间层。该层主要作用有三个:
- 系统调用为用户空间提供了一种硬件的抽象接口;
- 系统调用保证了系统的稳定和安全;
- 系统调用是用户空间访问内核的惟一手段。
API、POSIX、C库
应用程序通过API而不是直接通过系统调用来编程,因为应用程序使用的这种编程接口实际上并不需要和内核提供的系统调用对应。一个API定义了一组应用程序使用的编程接口。它们可以实现成一个系统调用,也可以通过多个系统调用来实现,而完全不使用任何系统调用也不存在问题。实际上,API可以在各种不同的操作系统上实现,给应用程序提供完全相同的接口,而它们本身在这些系统上的实现却可能迥异。linux中最流行的API是基于POSIX标准的。
linux的系统调用像大多数Unix系统一样,作为C库的一部分提供。C库实现了Unix系统的主要API,包括标准C库函数和系统调用。
系统调用
系统调用通常通过函数进行调用,函数返回0,代表执行成功,如果调用出现错误时,会把错误码写入errno全局变量,通过调用perror()库函数,可以把该变量翻译成用户可以理解的错误字符串。
在Linux中,每个系统调用被赋予一个系统调用号。当用户空间的进程执行一个系统调用的时候,这个系统调用号就用来指明到底是要执行哪一个系统调用。系统调用号相当关键,一旦分配就不能再有任何变更,否则编译好的应用程序就会崩溃。此外,如果一个系统调用被删除,它所占用的系统调用号也不允许回收利用,否则,以前编译过的代码会调用这个系统调用,但事实上却调用的是另一个系统调用。
Linux系统调用比其他许多操作系统执行得要快。Linux令人难以置信的上下文件切换时间是一个重要原因;进出内核都被优化得简洁高效。另外一个原因是系统调用处理程序和每一个系统调用本身也都非常简洁。
系统调用处理程序
用户空间的程序无法直接执行内核代码,它们不能直接调用内核空间中的函数,因为内核驻留在受保护的地址空间上。如果进程可以直接在内核的地址空间上读写的话,系统安全就会失去控制。
所以,应用程序应该以某种方式通知系统,告诉内核自己需要执行一个系统调用,希望系统切换到内核态,这样内核就可以代表应用程序来执行该系统调用了。
通知内核的机制是靠软中断实现的:通过引发一个异常来促使系统切换到内核态去执行异常处理程序。此时的异常处理实际上就是系统调用处理程序。除了系统调用号以外,大部分系统调用都还需要一些外部的参数输入。所以,在发生异常的时候,应该把这些参数从用户空间传给内核。
系统调用的实现
实现一个系统调用的第一步是决定它的用途。每个系统调用都应该有一个明确的用途。在Linux中不提倡用多用途的系统调用。然后,考虑新系统调用的参数、返回值和错误码是什么。新的系统调用必须检查它们所有的参数是否合法有效。
linux内核--系统调用