系统调用
理解系统调用
在现代操作系统中,内核提供了一组用户进程和内核交流的接口。这些接口让应用程序受限制地访问硬件资源,提供了创建新进程并与已有进程通信地机制,也提供了申请操作系统其他资源的能力。其作用是保证系统的稳定可靠,避免应用程序肆意妄为。
API、POSIX和C库
API定义了一组应用程序使用的编程接口,它们的实现可以使用一个或多个系统调用,甚至是完全不使用任何系统调用也没有问题。API可以在不同的操作系统上实现,但能为应用程序提供完全一样的接口(这些接口大多数都遵循POSIX标准)。
从纯技术的角度看,POSIX是由IEEE组成的一套标准,其目标是提供一套大体上基于Unix的可移植操作系统标准。
linux的系统调用像大多数Unix系统一样,作为C库的一部分提供。c库实现了Unix系统的主要API,包括标准c库函数和系统调用接口。所有C程序都可以使用C库。此外C库提供POSIX的绝大部分API。
注意:不要把C库和系统调用比较异同,属于是钻牛角尖,更容易混淆自己。两者就是密不可分,互相使用。
系统调用会通过一个long类型的返回值来表示成功或者错误。通常,用一个负的返回值表明错误;用0表明成功。系统调用在出现错误的时候会把错误码写入到errno全局变量,通过调用perror()库函数可以翻译成用户理解的字符串。
系统调用号
在linux中,每个系统调用都被赋予了一个系统调用号。通过这样一个独一无二的号,进程在执行系统调用时就无须提及系统调用的名称。
注意系统调用号非常重用,一旦分配了就不能再做任何变更。内核记录了系统调用表中所有已注册过的系统调用,存储在sys_call_table中。
系统调用处理程序
用户空间的程序无法直接执行内核代码(如果进程可以直接在内核空间读写的话,系统的稳定性和安全性将不复存在),所以应用程序应该以某种方式通知内核,告诉内核自己需要执行一个系统调用,希望内核切换到内核态,这样内核就可以代表应用程序在内核空间执行系统调用了。
通知内核的机制是靠软中断
实现的:通过引发一个异常来促使系统切换到内核态去执行异常处理程序。在x86上预定义的软中断号是128,通过执行int $0x80来触发中断 ,并执行第128号异常处理程序system_call()。
系统调用号
是通过寄存器
传递给内核的,在陷入内核之前用户空间就将系统调用对应的系统调用号放入了寄存器中。同理,函数的参数和返回值也是通过寄存器来进行传递的。
如何实现一个系统调用
略,一般用不到,真的需要,尽量使用别的方式代替。