linux读书笔记(5章)
标签(空格分隔): 20135328陈都
第五章 系统调用
5.1 与内核通信
- 系统调用
- 让应用程序受限的访问硬件设备
- 提供创建新进程并与已有进程通信的机制
- 提供申请操作系统其他资源能力
系统调用在用户空间进程和硬件设备之间添加了一个中间层。该层主要作用有三个。
- 首先,它为用户空间提供了一种硬件的抽象接口。举例来说,当需要读写文件的时候,应用程序就可以不去管磁盘类型和介质,甚至不用去管文件所在的文件系统到底是哪种类型。
- 第二,系统调用保证了系统的稳定和安全。作为硬件设备和应用程序之间的中间人,内核可以基于权限、用户类型和其他一些规则对需要进行的访问进行裁决。举例来说,这样可以避免应用程序不正确地使用硬件设备,窃取其他进程的资源,或做出其他危害系统的事情。
- 第三,每个进程都运行在虚拟系统中,而在用户空间和系统的其余部分提供这样一层公共接口,也是出于这种考虑。
5.2 API, POSIX 和C 库
- 一般情况下,应用程序通过在用户空间实现的应用编程接口(api)而不是直接通过系统调用来编程。
- 这点很重要,因为应用程序使用的这种编程接口实际上并不需要和内核提供的系统调用对应。
- 一个API 定义了一组应用程序使用的编程接口。
5.3 系统调用
要访问系统调用〈在Linux中常称作syscall),通常通过C库中定义的函数调用来进行。
5.3.1 系统调用号
- 在Linux 中,每个系统调用被赋予一个系统调用号。这样,通过这个独一无二的号就可以关联系统调用。当用户空间的进程执行一个系统调用的时候, 这个系统调用号就用来指明到底是要执行哪个系统调用:进程不会提及系统调用的名称。
- 内核记录了系统调用表中的所有已注册过的系统调用的列表,存储在sys_call_ table 中。每一种体系结构中,都明确定义了这个表,在x86-64中,它定义arch/i386/kemel/syscall_64.c文件中。这个表为每一个有放的系统调用指定了唯一的系统调用号。
5.3.2 系统调用的性能
Linux 系统调用比其他许多操作系统执行得要快。同时系统调用处理程序和每个系统调用本身也都非常简洁。
5.4 系统调用处理程序
用户空间的程序无摇直接执行内核代码。它们不能直接调用内核空间中的函数,因为内核驻留在受保护的地址空间上。
5.4.2 参撒传递
除了系统调用号以外,大部分系统调用都还需要一些外部的参数输入。所以,在发生陆入的时候,应该把这些参数从用户空间传给内核。最简单的办撞就是像传递系统调用号一样,把这些参数也存放在寄存器里。在x86-32 系统上, ebx, ecx、edx、esi和edi按照顺序存放前五个参数。需要六个或六个以上参数的情况不多见,此时,应该用一个单拙的寄存器存放指向所有这些参数在用户空间地址的指针。
5.5 系统调用的实现
实际上,一个Linux的系统调用在实现时并不需要太关心它和系统调用处理程序之间的关系。
记住Unix 的格言:“提供机制而不是策略”。
当你写一个系统调用的时候,要时刻注意可移植性和健壮性,不但要考虑当前,还要为将来做打算。基本的Unix系统调用经受住了时间的考验:它们中的很大一部分到现在都还和30 年前一样适用和有效。
为什么不提倡用系统调用实现
建立一个新的系统调用的好处:
- 系统调用创建容易且使用方便。
- Linux 系统调用的高性能显而易见。
问题是: - 你需要一个系统调用号,而这需要一个内核在处于开发版本的时候由官方分配给你。
- 系统调用被加入稳定内核后就被固化了,为了避免应用程序的崩棚,它的接口不允许傲改动。
- 需要将系统调用分别注册到每个需要支持的体系结构中去。
- 在脚本中不容易调用系统调用,也不能从文件系统直接访问系统调用。
- 由于你需要系统调用号,因此在主内核树之外是很难维护和使用系统调用的。
- 如果仅仅进行简单的信息交换,系统调用就大材小用了。
替代方法 - 某些接口可以用文件描述符表示
- 把增加的信息作为文件放在sysfs的合适位置
总结
对于Unix的格言,我在网上查了很多,觉得大家讲的都很有道理,把所学用在生活中也是不错的。
区别对待机制(mechanism)和策略(policy)是Unix设计中的一大亮点。大部分的编程问题都可以被切割成两个部分:“需要提供什么功能”(机制)和“怎样实现这些功能”(策略)。如果由程序中的独立部分分别负责机制和策略的实现,那么开发软件就更容易,也更容易适应不同的需求。
如果说机制是一种框架,那么,策略就是填充框架的一个个具体实体。机制提供的是一种开放而宽松的环境,而策略就是在这个环境下赖以生存的生命个体。比如,我们编写的一个程序,fork()以后,就成为一个个进程的生命个体。而操作系统所提供给我们创建、执行以及结束进程的各种原语-fork(),exex()和exit()等是统管各种进程的机制。我们所创建进程的死活并不会影响机制本身。
参考资料:《Linux内核设计与实现》(原书第三版)