5.1 内核通信
系统调用在用户空间和硬件设备之间添加了一个中间层.
该层主要作用:
1.为用户空间提供了一种硬件的抽象接口.
2.保证了系统的稳定和安全.
3.每个进程都运行在虚拟系统中.
在Linux中,系统调用是用户空间访问内核的唯一手段;除异常和陷入外,它们是内核唯一的合法入口。
5.2 API、POSIX和C库
一般情况下,应用程序通过在用户空间实现的应用编程接口,而不是直接通过系统调用来编程。
一个API定义了一组应用程序使用的编程接口。
1.在Unix世界中,最流行的应用编程接口是基于POSIX标准的。
POSIX是由IEEE的一组标准组成。
2.C库实现了Unix系统的主要API,包括标准C库函数和系统调用接口。所有的C程序都可以使用C库,而其他语言也可以把他们封装起来使用。
3.Unix接口设计中,“提供机制而不是策略”,Unix系统调用抽象出了完成某种确定目的的函数。
5.3系统调用
要访问系统调用,通常通过C库中定义的函数调用来进行。它们通常都需要定义零个、一个或几个参数(输入)而且可能产生一些副作用。
系统调用还会通过一个long类型的返回值来表示成功或者错误。
通常,也不绝对,用一个负的返回值来表明错误。返回一个0值通常表明成功。
系统调用在出现错误的时候C库会把错误码写入error全局变量。通过调用perror()库函数,可以把该量编译成用户可以理解的错误字符串。
如何定义系统调用?
1.限定词。
2.函数返回。注意返回值类型。
3.系统调用在内核中被定义时有命名规则。Get_pid()为sys_getpid()。
5.3.1 系统调用号
指明要执行哪个系统调用,进程不会提及系统调用的名称。
一旦分配就不能再有变更,否则编译好的程序就会崩溃。
如果一个系统调用被删除,它所占用的系统调用号也不允许被回收利用。
Sys_ni_syscall():除了返回-ENOSYS外不做任何其他工作,这个错误号专门针对无效的系统调用而设的。
5.3.2 系统调用的性能
为什么Linux系统调用执行快?
1.Linux的上下文切换时间很短。
2.系统调用处理程序和每个系统调用本身也非常简洁。
5.4 系统调用处理程序
用户空间的程序无法直接执行内核代码。
软中断:应用程序通知系统的机制。通过引发一个异常来促使系统切换到内核态去执行异常处理程序。
5.4.1 指定恰当的系统调用
X86中,系统调用号是通过eax寄存器传递给内核的。
5.4.2 参数传递
在x86-32系统上,ebx\ecx\edx\esi和edi按照顺序存放前五个参数。
给用户空间的返回值存放在eax寄存器中。
5.5 系统调用的实现
5.5.2 参数验证
在接受一个用户空间的指针之前,内核必须保证:
内核无论何时都不能轻率的接受来自用户空间的指针!
5.6 系统调用上下文
在进程上下文中,内核可以休眠,也可以被抢占。