《Linux内核设计与实现》第四周读书笔记——第五章
5.1 与内核通信57
系统调用在用户空间进程和硬件设备之间添加了一个中间层,该层主要作用有三个:
- 首先它为用户空间提供了一种硬件的抽象接口,举例来说当需要读写文件的时候,应用程序就可以不去管磁盘类型和介质,甚至不用去管文件所在的文件系统到底是哪种类型。
- 第二,系统调用保证了系统的稳定和安全,作为硬件设备和应用程序之间的中间人,内核可以基于权限、用户类型和其他一些规则对需要进行的访问进行裁决,举例来说,这样可以避免应用程序不正确地使用硬件设备,窃取其他进程的资源,或做出其他危害系统的事情。
- 第三,在第3章中曾经提到过,每个进程都运行在虚拟系统中,而在用户空间和系统的其余部分提供这样一层公共接口,也是出于这种考虑,如果应用程序可以随意访问硬件而内核又对此一无所知的话几乎就没法实现多任务和虚拟内存,当然也不可能实现良好的稳定性和安全性。
在Linux中,系统调用是用户空间访问。内核的唯一手段;除异常和陷入外,它们是内核唯一的合法入口。
本章重点强调Linux系统调用的规则和实现方法。
5.2 API、POSIX和C库57
- 一般情况下,应用程序通过在用户空间实现的应用编程接口而不是直接通过系统调用来编程。
- 应用程序使用的这种编程接口实际上并不需要和内核提供的系统调用对应。一个API定义了一组应用程序使用的编程接口,它们可以实现成一个系统调用,也可以通过调用多个系统调用来实现,而完全不使用任何系统调用也不存在问题。
- 实际上,API可以在各种不同的操作系统实现,给应用程序提供完全相同的接口,而它们本身在这些系统上的实现却可能迥异。
- API、POSIX和C库以及系统调用之间的关系如下图
图一 - 在Unix世界中,最流行的应用编程接口是基于POSIX标准的。
- 关于Unix的接口设计有一句格言:提供机制而不是策略。
5.3 系统调用58
- 要访问系统调用,通常通过C库中定义的函数调用来进行。
- 系统调用最终具有一种明确的操作。
- 如何定义系统调用
首先,注意函数声明中的asmlinkage限定词,这是一个编译指令,通知编译器仅从栈中提取该函数的参数。所有的系统调用都需要这个限定词。
其次函数返回long。为了保证32位和64位系统的兼容,系统调用在用户空间和内核空间有不同的返回值类型,在用户空间为int在内核空间为long。
最后,注意系统调用get_pid()中的在内核中被定义成sys_getpid()。这是Linux中所有系统调用都应该遵守的命名规则,系统调用bar()在内核中也实现为sys_bar()函数。
实验过程:
1、库函数API使用系统调用
2、C代码中嵌入汇编代码使用系统调用
3、实验结果