1.3 系统函数
Linux内核本身作为一个独立的系统不能完成我们需要的业务功能,只有结合系统的应用程序,成为业务系统的一部分,完成需要的业务功能。
Linux操作系统由4个主要的子系统所组成:
(1)用户应用程序——在某个特定的Linux系统上运行的应用程序集合,它将随着设备用途不同而发生变化,但一般会包括文字处理应用程序和Web浏览器等基本业务。
(2)O/S服务——这些服务一般认为是操作系统的一部分(开窗系统,命令外壳程序等);此外,内核的编程接口(编译工具和库)也属于这个子系统。
(3)Linux内核——这是本文的关注焦点,包括内核抽象和对硬件资源(如CPU)的间接访问。
(4)硬件控制器——这个子系统包含在Linux实现中所有可能的物理设备,例如,CPU、内存硬件、硬盘以及网络硬件等都是该子系统的成员。
1.系统调用
我们用很少量的函数就可以对文件和设备进行访问和控制,这些函数被称为系统调用,由Linux系统直接提供,它们也是通向操作系统本身的接口。
Linux系统调用部分是非常精简的系统调用(只有250个左右),它继承了UNIX系统调用中最基本和最有用的部分。这些系统调用按照功能逻辑大致可分为进程控制、进程间通信、文件系统控制、系统控制、存储管理、网络管理、socket控制、用户管理等几类。
所谓系统调用是指操作系统提供给用户程序调用的一组“特殊”接口,用户程序可以通过这组“特殊”接口来获得操作系统内核提供的服务。为什么用户程序不能直接访问系统内核提供的服务呢?这是由于在Linux中,为了更好地保护内核空间,将程序的运行空间分为内核空间和用户空间(也就是常称的内核态和用户态),它们分别运行在不同的级别上,在逻辑上是相互隔离的。因此,用户进程在通常情况下不允许访问内核数据,也无法使用内核函数,它们只能在用户空间操作用户数据,调用用户空间的函数。
但是,在有些情况下,用户空间的进程需要获得一定的系统服务(调用内核空间程序),这时操作系统就必须利用系统提供给用户的“特殊接口”——系统调用规定用户进程进入内核空间的具体位置。进行系统调用时,程序运行空间需要从用户空间进入内核空间,处理完后再返回到用户空间。
2.库函数
直接使用底层系统调用的问题是它们的效率非常低,系统调用会影响系统的性能。与函数调用相比,系统调用的开销要大些,因为在执行系统调用时,Linux必须从用户代码切换到内核代码运行,然后再返回用户代码,这种切换会影响函数调用的效率。减少这种开销的好方法是,在程序中尽量减少系统调用的次数,并且让每次系统调用完成尽可能多的工作。另外硬件会对底层系统调用一次所能读/写的数据块做一定的限制,系统调用的使用方式也受到这方面的限制。
为了给设备和磁盘文件提供更高层的接口,与UNIX一样,Linux发行版提供了一系列的标准函数库。它们是由一些函数构成的集合,可以把它们包含在自己的程序中去处理那些与设备和文件有关的问题。提供输出缓冲功能的标准IO库就是一个这样的例子,该库可以高效地写任意长度的数据块,函数则在数据满足数据块长度要求时安排执行底层系统调用,这样较大地降低了系统调用的负面影响。
Linux系统中各种文件函数与用户、设备驱动程序、内核和硬件之间的关系,如图1-1所示。
图1-1 系统调用与库函数关系图