1.1 Linux系统调用和用户程序编程接口
1.1.1 系统调用
操作系统负责管理和分配所有的计算机资源。为了更好地服务于应用程序,操作系统提供了一组特殊接口—系统调用。通过这组接口,用户程序可以使用操作系统内核提供的各种功能,如分配内存、创建进程、实现进程之间的通信等。
为什么不允许程序直接访问计算机资源?答案是不安全。单片机开发中,由于不需要操作系统,所以开发人员可以编写代码直接访问硬件。而在嵌入式系统中通常都要运行操作系统,程序访问资源的方式就发生了改变。操作系统基本上都支持多任务,即同时可以运行多个程序。如果允许程序直接访问系统资源,肯定会带来很多问题。因此,所有软硬件资源的管理和分配都由操作系统负责。程序要获取资源(如分配内存、读写串口)必须通过操作系统来完成,即用户程序向操作系统发出服务请求,操作系统收到请求后执行相关的代码来处理。
用户程序向操作系统提出请求的接口就是系统调用。所有的操作系统都会提供系统调用接口,只不过不同的操作系统提供的系统调用接口各不相同。Linux 系统调用接口非常精简,它继承了 UNIX 系统调用中最基本和最有用的部分。这些系统调用按照功能大致可分为进程控制、进程间通信、文件系统控制、存储管理、网络管理、套接字控制、用户管理等。
1.1.2 用户程序编程接口
前面提到利用系统调用接口程序可以访问各种资源,但在实际开发中程序并不直接使用系统调用接口,而是使用用户程序编程接口(API)。为什么不直接使用系统调用接口呢?原因如下。
(1)系统调用接口功能非常简单,无法满足程序的需求。
(2)不同操作系统的系统调用接口不兼容,程序移植时工作量大。
用户程序编程接口通俗的解释就是各种库(最重要的就是 C 库)中的函数。为了提高开发效率,C 库中实现了很多函数。这些函数实现了常用的功能,供程序员调用。这样一来,程序员不需要自己编写这些代码,直接调用库函数就可以实现基本功能,提高了代码的复用率。使用用户程序编程接口还有一个好处:程序具有良好的可移植性。几乎所有的操作系统上都实现了C 库,所以程序通常只需要重新编译一下就可以在其他操作系统下运行。
用户程序编程接口(API)在实现时,通常都要依赖系统调用接口。例如,创建进程的 API 函数 fork()对应于内核空间的 sys_fork()系统调用。很多 API 函数需要通过多个系统调用来完成其功能。还有一些 API 函数不需要调用任何系统调用。
在 Linux 中,用户程序编程接口(API)遵循了在 UNIX 中最流行的应用编程界面标准—POSIX 标准。POSIX 标准是由 IEEE 和 ISO/IEC 共同开发的标准系统,该标准基于当时的 UNIX 实践和经验,描述了操作系统的系统调用编程接口(实际上就是 API),用于保证应用程序可以在源代码一级上在多种操作系统上移植运行。这些系统调用编程接口主要是通过C 库(libc)实现的。