基于上一篇文章,系统调用的实现原理,计算机系统的各种硬件资源是有限的,而在现代多任务操作系统上的多个进程都需要这些资源,为了更好的管理这些资源,进程是不允许直接访问的,而是在操作系统的控制下访问,因此操作系统是使用这些资源的唯一入口,而这个入口就是操作系统的系统调用,系统调用属于系统内核的一部分,因此运行在内核态的进程可以直接访问这些资源,而用户态的进程如果想要访问需要先通过中断切换为内核态才可以访问。 Linux中处理系统调用的方式与中断类似。每个系统调用都有相应的系统调用号作为唯一的标识,内核维护一张系统调用表,表中的元素是系统调用函数的起始地址,而系统调用号就是系统调用在调用表的偏移量。在进行系统调用是只要指定对应的系统调用号,就可以明确的要调用哪个系统调用,这就完成了系统调用的函数名称的转换。对于参数传递,Linux是通过寄存器完成的。系统调用很耗时,第一,系统调用通过中断实现,需要完成栈切换。第二,使用寄存器传参,这需要额外的保存和恢复的过程。
而库函数处于用户态,库函数是对于系统调用的封装。这样的话,就可以减少系统调用栈切换的时间消耗。 但是不是所有的库函数都有对应的系统调用, 当然,还有很多库函数对应于一条系统调用,比如exec()。
以存储器分配函数malloc为例。有多种方法可以进行存储器分配及与其相关的无用区收集操作(最佳适应,首次适应等),并不存在对所有程序都最佳的一种技术。Unix系统调用中处理存储器分配的是sbrk(2),它不是一个通用的存储器管理器。它增加或减少指定字节数的进程地址空间。如何管理该地址空间却取决于进程。存储器分配函数malloc(3)实现一种特定类型的分配。如果我们不喜欢其操作方式,则我们可以定义自己的malloc函数,极 其可能,它还是要调用sbrk系统调用。事实上,有很多软件包,它们实现自己的存储器分配算法,但仍使用sbrk系统调用。从中可见,两者职责不同,相互分开,要核中的系统调用分配另外一块空间给进程,而库函数malloc则管理这种空间。
系统调用是操作系统的一部分,各个操作系统的系统调用是不同的,而在所有的ANSI C编译器版本中,C库函数是相同的,系统调用是调用系统内核的服务,在内核地址空间运行,需要在用户空间和内核上下文环境切换,开销较大。而库函数调用属于过程调用,开销较小,典型的C函数库调用:system
fprintf malloc。典型的系统调用:chdir fork write brk;