系统调用(SYSTEM CALL)
OS内核中都有一组实现系统功能的过程,系统调用就是对上述过程的调用。编程人员利用系统调用,向OS提出服务请求,由OS代为完成。
一般情况下,进程是不能够存取系统内核的。它不能存取内核使用的内存段,也不能调用内核函数,CPU的硬件结构保证了这一点。只有系统调用是一个例外。
统调用是用户态进入内核态的唯一入口:一夫当关,万夫莫开。常用系统调用:
- 控制硬件:如write/read调用。
- 设置系统状态或读取内核数据——getpid()、getpriority()、setpriority()、sethostname()
- 进程管理:如 fork()、clone()、execve()、exit()等
优点 编程容易,从硬件设备的低级编程中解脱出来 提高了系统的安全性,可以先检查请求的正确性
陷入指令
在 Intel CPU 中,这个指令由中断 0x80 实现。
在 ARM 中,这个指令是 SWI。
Int 0x80指令
Linux中实现系统调用利用了i386体系结构中的软件中断。即调用了int $0x80汇编指令。
这条汇编指令将产生向量为128的编程异常,CPU便被切换到内核态执行内核函数,转到了系统调用处理程序的入口:system_call()。
int $0x80指令将用户态的执行模式转变为内核态,并将控制权交给系统调用过程的起点system_call()处理函数。
system_cal()检查系统调用号,该号码告诉内核进程请求哪种服务。
内核进程查看系统调用表(sys_call_table)找到所调用的内核函数入口地址。
接着调用相应的函数,在返回后做一些系统检查,最后返回到进程。
system_call()函数
系统调用和普通函数调用
API是用于某种特定目的的函数,供应用程序调用,而系统调用供应用程序直接进入系统内核。
Linux内核提供了一些C语言函数库,这些库对系统调用进行了一些包装和扩展,因为这些库函数与系统调用的关系非常紧密,所以习惯上把这些函数也称为系统调用。
有的API函数在用户空间就可以完成工作,如一些用于数学计算的函数,因此不需要使用系统调用。
有的API函数可能会进行多次系统调用。
不同的API 函数也可能会有相同的系统调用。比如malloc(),calloc(),free()等函数都使用相同的方法分配和释放内存。
系统命令、内核函数
系统调用与系统命令
- 系统命令相对API来说,更高一层。每个系统命令都是一个执行程序,如ls命令等。这些命令的实现调用了系统调用。
系统调用与内核函数
- 系统调用是用户进入内核的接口层,它本身并非内核函数,但是它由内核函数实现。
- 进入内核后,不同的系统调用会找到各自对应的内核函数,这些内核函数被称为系统调用的“服务例程”。如系统调用getpid实际调用的服务例程为sys_getpid(),或者说系统调用getpid()是服务例程sys_getpid()的封装例程。
封装例程(wrapper routine)
<