《Linux内核设计与实现》读书笔记(三)--系统调用

  系统调用:为保证系统稳定可靠,避免应用程序肆意妄行。用户进程与内核进行交互的一组接口。

1、与内核通信

  系统调用在用户空间进程和硬件设备之间添加了一个中间层。该层有三个主要作用:

  1. 为用户空间提供了一种硬件的抽象接口;
  2. 保证了系统的稳定和安全;
  3. 保证每个进程都运行在虚拟系统中。

  系统调用是用户空间访问内核的唯一手段;除异常和陷入外,它们是内核唯一的合法入口。
  用户程序,系统调用,内核,硬件设备的调用关系如下图:
这里写图片描述

2、API、POSIX和C库

  应用程序通过在用户空间实现的应用编程接口(API)而不是直接通过系统调用来编程。一个API定义了一组应用程序使用的编程接口,可对应多个系统调用。
  POSIX是一套应用编程接口(API)的实现标准。
  C库实现了linux系统的主要API,包括标准C库函数和系统调用接口。
  从程序员角度看,系统调用无关紧要,只需要跟API打交道就可以了,相反,内核只跟系统调用打交道;库函数及应用程序怎么使用系统调用,内核无需关心;但内核必须时刻牢记系统调用所有潜在的用途,并保证它们有良好的通用性和灵活性。

3、系统调用

  要访问系统调用(syscall),通常通过C库中定义的函数调用来进行。
  asmlinkage:用于函数声明的限定词,一个编译指令,通知编译器仅从栈中提取该函数的参数。所有系统调用都需要这个限定词。

3.1 系统调用号

  在Linux中,每个系统调用都被赋予一个系统调用号。通过这个独一无二的号可以准确的关联系统调用。
  系统调用号非常重要,一旦分配就不能再有任何变更。系统调用就算被删除,其所占用的系统调用号也不允许被回收利用。
  内核记录了系统调用表中的所有已注册过的系统调用的列表,存储在sys_call_table中。该表为每一个有效的系统调用指定了唯一的系统调用号。

3.2 系统调用的性能

  Linux系统调用比其他许多操作系统执行的要快。Linux很短的上下文切换是一个重要原因,进出内核都被优化得简洁高效。同时系统调用处理程序和每个系统调用本身都非常简洁。

4、系统调用处理程序

  用户空间通知内核的机制:依靠软中断实现:通过引发一个异常来促使系统切换到内核态去执行异常处理程序。此时的异常处理程序实际上就是系统调用处理程序system_call()。

4.1 指定恰当的系统调用

  在x86上,系统调用号通过eax寄存器传递到内核。在陷入内核之前,用户空间就把相应系统调用所对应的号放入eax寄存器中。
  system_call()函数通过将给定的系统调用号与NR_syscalls做比较来检查其有效性。如果它大于或等于NR_syscalls,该函数就返回-ENOSYS。否则,就执行相应的系统调用:

    call *sys_call_table(,%rax,8);

4.2 参数传递

  除了系统调用号以外,大部分系统调用都还需要一些外部的参数输入。类似系统调用号的做法,也把这些参数存放在寄存器里。在x86-32系统上,ebx、ecx、edx、esi核sdi按照顺序存放前五个参数。

5、系统调用的实现

5.1 实现系统调用

  实现一个新的系统调用首先要决定它的用途。每个系统调用都应该有一个明确的用途。
  确定新系统调用的参数、返回值和错误码。系统调用的接口应该力求简洁,参数尽可能少。稳定!!!
  设计接口时要尽量为将来多做考虑。系统调用设计的越通用越好。不要假设这个系统调用现在怎么用将来也一定就是这么用。永远记住Uinx的格言:提供机制而不是策略!
  实现新的系统调用时,要时刻注意可移植性和健壮性,不但要考虑当前,还要为将来做打算。基本的Unix系统调用经受住了时间的考验;他们中的很大一部分现在还和30年前一样适用和有效。

5.2 参数验证

  系统调用必须仔细检查它们所有的参数是否合法有效。系统调用在内核控件执行,如果任由用户将不合法的输入传递给内核,那么系统的安全和稳定将面临极大的考验。
  最重要的检查就是检查用户提供的指针是否有效。在接受一个用户空间的指针之前,内核必须保证:

  1. 指针指向的内存区域属于用户空间。
  2. 指针指向的内存区域在进程的地址空间里。
  3. 如果是读,该内存应被标记为可读;如果是写,该内存应被标记为可写;如果是可执行,该内存被标记为可执行。

  copy_to_user():向用户空间写入数据;
  copy_from_user():从用户空间读取数据。

6、系统调用上下文

  内核在执行系统调用的时候处于进程上下文。current指针指向当前任务,即引发系统调用的那个进程。
  在进程上下文中,内核可以休眠并且可以被抢占。(一)能够休眠说明系统调用可以使用内核提供的绝大部分功能;(二)在进程上下文中能被抢占其实表明,像用户空间内的进程一样,当前的进程同样可以被其他进程抢占。

6.1 绑定一个系统调用的最后步骤

  当编写完一个系统调用后,把它注册成一个正式的系统调用是件琐碎的工作:

  1. 首先,在系统调用表的最后加入一个表项;
  2. 对于所支持的各种体系结构,系统调用号都必须定义于《asm/unistd.h》中;
  3. 系统调用必须被便衣进内核映像(不能被编译成模块)。

6.2 从用户空间访问系统调用

  系统调用通常靠C库支持。用户程序通过包含标准头文件并和C库链接,就可以使用系统调用。

6.3 系统调用的利弊

  建立一个新的系统调用的好处:

  • 系统调用创建容易且使用方便;
  • Linux系统调用的高性能显而易见。

  缺点:

  • 需要一个系统调用号,而这需要一个内核在处于开发版本的时候由官方分配给你;
  • 系统调用被加入稳定内核后就被固化了,为避免应用程序的崩溃,它的接口不允许做改动;
  • 需要将系统调用分别注册到每个需要支持的体系结构中去;
  • 在脚本中不容易调用系统调用,也不能从文件系统直接访问系统调用;
  • 由于需要系统调用号,因此在主内核树之外是很难维护和使用系统调用的;
  • 如果仅仅进行简单的信息交换,系统调用就大材小用了。

  替代方案:
  实现一个设备节点,并对此实现read()和write()。使用ioctl()对特定的设置进行操作或者对特定的信息进行检索。

  • 像信号量这样的某些接口,可以用文件描述符来表示,因此也就可以按上述方式对其进行操作;
  • 把增加的信息作为一个文件放在sysfs的合适位置。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值