系统调用、用户编程接口(API)、系统命令、和内核函数的关系
系统调用并非直接和程序员或系统管理员打交道,它仅仅是一个通过软中断机制(我们后面讲述)向内核提交请求,获取内核服务的接口。而在实际使用中程序员调用的多是用户编程接口——API,而管理员使用的则多是系统命令。
用户编程接口其实是一个函数定义,说明了如何获得一个给定的服务,比如read()、malloc()、free()、abs()等。它有可能和系统调用形式上一致,比如read()接口就和read系统调用对应,但这种对应并非一一对应,往往会出现几种不同的API内部用到统一个系统调用,比如malloc()、free()内部利用brk( )系统调用来扩大或缩小进程的堆;或一个API利用了好几个系统调用组合完成服务。更有些API甚至不需要任何系统调用——因为它不必需要内核服务,如计算整数绝对值的abs()接口。
另外要补充的是Linux的用户编程接口遵循了在Unix世界中最流行的应用编程界面标准——POSIX标准,这套标准定义了一系列API。在Linux中(Unix也如此)这些API主要是通过C库(libc)实现的,它除了定义的一些标准的C函数外,一个很重要的任务就是提供了一套封装例程(wrapper routine)将系统调用在用户空间包装后供用户编程使用。
不过封装并非必须的,如果你愿意直接调用,Linux内核也提供了一个syscall()函数来实现调用,我们看个例子来对比一下通过C库调用和直接调用的区别。
#include
#include
#include
#include
int main(void) {
long ID1, ID2;
/*—————————–*/
/* 直接系统调用*/
/* SYS_getpid (func no. is 20) */
/*—————————–*/
ID1 = syscall(SYS_getpid);
printf (“syscall(SYS_getpid)=%ld\n”, ID1);
/*—————————–*/
/* 使用”libc”封装的系统调用 */
/* SYS_getpid (Func No. is 20) */
/*—————————–*/
ID2 = getpid();
printf (“getpid()=%ld\n”, ID2);
return(0);
}
系统命令相对编程接口更高了一层,它是内部引用API的可执行程序,比如我们常用的系统命令ls、hostname等。Linux的系统命令格式遵循系统V的传统,多数放在/bin和/sbin下(相关内容可看看shell等章节)。
有兴趣的话可以通过strace ls或strace hostname 命令查看一下它们用到的系统调用,你会发现诸如open、brk、fstat、ioctl 等系统调用被用在系统命令中。