第五章 系统调用

5.1 与内核通信

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

  • 为用户空间提供了硬件的抽象接口。
  • 系统调用保证了系统的稳定和安全。
  • 实现多任务和虚拟内存,保证良好的稳定性和安全性。

2.系统调用是用户空间访问内核的唯一手段;除异常和陷入外,是内核唯一合法的入口。

5.2 API、POSIX和C库

1.情况下,应用程序通过在用户空间实现的应用编程接口(API)而不是直接通过系统调用来编程。

2.C库提供了POSIX的绝大部分API。

5.3 系统调用

1.要访问系统调用(syscall),通常通过C库中定义的函数调用来进行。

2.如何定义系统调用,注意:

  • asmlinkage为限定词,是一个编译指令,通知编译器仅从栈中提取该函数的参数。
  • 函数返回long。
  • 系统调用get_pid()在内核中被定义为sys_getpid()。

5.3.1系统调用号

1.在Linux系统中,每个系统调用被赋予一个系统调用号,这样通过这个第一无二的号就可以关联系统调用。当用户空间的进程执行一个系统调用时,系统调用号用来指明执行哪个系统调用;进程不会提及系统调用的名称。

2.系统调用号一旦分配就不会再有任何变更,否则编译好的应用程序就会崩溃。如果一个系统调用被删除,所占用的系统调用号也不许被回收利用。sys _ ni _ syscall()专门针对无效的系统调用而设立的,只返回-ENOSYS。

3.内核记录了系统调用表中的所有已注册的系统调用的列表,存储在sys_call_table中。在x86-64中,他被定义于3arch/i386/kernel/syscall_64.c文件中,为每一个有效的系统调用指定唯一的系统调用号。

5.3.2系统调用的的性能

1.很短的上下文切换时间

2.系统调用处理程序和每个系统调用本身都很简洁。

5.4 系统调用处理程序

5.4.1指定恰当的系统调用

1.在X86中,系统调用号通过eax寄存器传递给内核,system _ call()函数通过将给定的系统调用与NR _syscalls作比较来检查其有效性,如果大于或等于NR _syscalls就返回-ENOSYS,否则就执行相应的系统调用:

call *sys_call_table(,%eax,8)//基址+偏移量*8

5.5系统调用的实现

5.5.1 实现系统调用

  • 他要做些什么
  • 新系统调用的参数、返回值和错误码又该是什么?
  • 系统调用设计的越通用越好
  • 时刻注意可移植性和健壮性

5.5.2参数验证

1.系统调用必须仔细检查所有的参数是否合法有效,而且必须是正确的。

2.最重要的一种检查是检查用户提供的指针是否有效,在接收一个用户空间的指针之前,内核必须保证:

  • 指针所指向的内存区域属于用户空间。
  • 指针所指向的内存区域在进程的地址空间之内。
  • 如果是读,该内存应被标记为可读,如果是写,该内存应被标记为可写,如果是可执行,该内存应被标记为可执行。进程决不能绕过内存访问限制。

3.内核提供了两个方法来完成必须的检查内核空间与用户空间数据的来回拷贝。

  • 为了向用户空间写数据,内核提供了copy _ to _user(),它需要三个参数,第一个是进程空间中的目的内存地址,第二个是内核空间内的源地址,第三个是需要拷贝的数据长度(字节数)。

  • 为了从用户空间读数据,内核提供了copy _ from _user(),该函数把第二个参数指定位置上的数据拷贝到第一个参数的指定位置,第三个是需要拷贝的数据长度(字节数)。

如果运行成功,则返回0,如果失败,则返回没能拷贝成功的字节数。

4.检查针对是否有合法权限

调用capable()函数检查用户是否有权对指定资源进行操作,返回非0值则有权限,返回0无权限。

<linux/capability.h>中包含一份所有权能和其对应的权限列表。

5.6 系统调用上下文

1.内核在执行系统调用时处于进程上下文。在进程上下文中,内核可以:

  • 休眠:说明系统调用可以使用内核提供的绝大部分功能。
  • 可以被抢占:要求保证该系统调用是可重入的。

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

  1. 在系统调用表的最后加入一个表项。
  2. 对于所支持的各种体系结构,系统调用号都必须定义于<asm/unistd.h>中。
  3. 系统调用必须被编译进内核映像(不能被编译成模块)。只要将其放进kernel/下的一个相关文件中即可,例如sys.c,它包含了各种各样的系统调用。

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

1.通常,系统调用靠C库支持。

2.Linux本身提供了一组宏,用于直接对系统调用进行访问。他会设置好寄存器并调用陷入指令。

3.对于每个宏来说,都有(2+2xn)个参数:

  • 第一个参数是系统调用的返回值类型
  • 第二个参数是系统调用的名称
  • 再以后是按照系统调用参数的顺序排列每个参数的类型和名称。
  • _ NR _open在<asm/unistd.h>中定义,是系统调用号。这个宏会被扩展成为内嵌汇编的C函数。

5.6.3 为什么不通过系统调用的方式实现

好处:

  • 系统调用创建容易并且使用方便
  • linux系统调用的高性能

问题:

  • 你需要―个系统调用号,而这需要一个内核在处于开发版本的时候由官方分配给你
  • 系统调用被加入稳定内核后就被固化了,它的接口不允许做改动
  • 需要将系统调用分别注册到每个需要支持的体系结构中去
  • 在脚本中不容易调用系统调用,也不能从文件系统直接访问系统调用
  • 由于你需要系统调用号,因此在主内核树之外是很难维护和使用系统调用的

替代方法:

实现一个设备节点,并对此实现read()和write()。使用特定的信息进行检索。

  • 像信号量这样的某些接口,可以用文件描述符来表示,因此也就可以按上述方式对其进行操作
  • 把增加的信息作为一个文件放在sysfs的合适位置

Linux内核分析 读书笔记 (第五章)的更多相关文章

  1. Linux内核分析 读书笔记 (第一章、第二章)

    第一章 Linux内核简介 1.1 Unix的历史 Unix很简洁,仅仅提供几百个系统调用并且有一个非常明确的设计目的. 在Unix中,所有东西都被当做文件,这种抽象使对数据和对设备的操作是通过一套相 ...

  2. 20135239 益西拉姆 linux内核分析 读书笔记之第四章

    chapter 4 进程调度 4.1 多任务 多任务操作系统就是能同时并发的交互执行多个进程的操作系统. 多任务系统可以划分为两类: - 非抢占式多任务: - 进程会一直执行直到自己主动停止运行(这一 ...

  3. Linux内核分析 读书笔记 (第三章)

    第三章 进程管理 3.1 进程 1.进程: 进程就是处于执行期的程序. 进程就是正在执行的程序代码的实时结果. 进程是处于执行期的程序以及相关的资源的总称. 进程包括代码段和其他资源. 2.线程:执行 ...

  4. Linux内核分析 读书笔记 (第四章)

    第四章 进程调度 调度程序负责决定将哪个进程投入运行,何时运行以及运行多长时间.进程调度程序可看做在可运行态进程之间分配有限的处理器时间资源的内核子系统.只有通过调度程序的合理调度,系统资源才能最大限 ...

  5. Linux内核分析 读书笔记 (第七章)

    第七章 链接 1.链接是将各种代码和数据部分收集起来并组合成为一个单一文件的过程,这个文件可被加载(或被拷贝)到存储器并执行. 2.链接可以执行于编译时,也就是在源代码被翻译成机器代码时:也可以执行于 ...

  6. Linux内核分析 读书笔记 (第十八章)

    第十八章 调试 18.1 准备开始 1. 需要的只是: 一个bug 一个藏匿bug的内核版本 相关内核代码的知识和运气 2. 在跟踪bug的时候,掌握的信息越多越好. 18.2 内核中的bug 1.  ...

  7. 《Linux内核设计与实现》第四周读书笔记——第五章

    <Linux内核设计与实现>第四周读书笔记--第五章 20135301张忻 估算学习时间:共1.5小时 读书:1.0 代码:0 作业:0 博客:0.5 实际学习时间:共2.0小时 读书:1 ...

  8. 《Linux内核设计与实现》读书笔记——第五章

    <Linux内核设计与实现>读书笔记--第五章 标签(空格分隔): 20135321余佳源 第五章 系统调用 操作系统中,内核提供了用户进程与内核进行交互的一组接口.这些接口让应用程序受限 ...

  9. Linux内核分析课程笔记(一)

    linux内核分析课程笔记(一) 冯诺依曼体系结构 冯诺依曼体系结构实际上就是存储程序计算机. 从两个层面来讲: 从硬件的角度来看,冯诺依曼体系结构逻辑上可以抽象成CPU和内存,通过总线相连.CPU上 ...

随机推荐

  1. Orcale新增、修改、删除字段

    一.新增字段 alert table user add( userName VARCHAR2(255 CHAR) ) ; 设置字段不为空, 给出默认值 alert table user add( us ...

  2. hadoop系列 第三坑: Task process exit with nonzero status of 137

    跑MR的时候抛出异常: java.lang.Throwable: Child Error at org.apache.hadoop.mapred.TaskRunner.run(TaskRunner.j ...

  3. vue中使用baidushare分享到微信无法显示bug解决方案

    最近vue单页面项目中有个页面分享的功能需求,按以往经验,选择了百度开源的baidushare.js 经过一天的挣扎,终于弄清楚了分享到微信后无法显示的原因. 对比分析: 以往成功使用:另写了一个专门 ...

  4. sql 查询重复行数据

    1.查找表中多余的重复记录,重复记录是根据单个字段(peopleId)来判断select * from peoplewhere peopleId in (select  peopleId  from  ...

  5. vue实例详解

    Vue实例的构造函数 每个 Vue.js 应用都是通过构造函数 Vue 创建一个 Vue 的根实例 启动的 虽然没有完全遵循 MVVM 模式, Vue 的设计无疑受到了它的启发.因此在文档中经常会使用 ...

  6. CF 932E Team Work

    原题题面 题目大意:求\(\sum\limits_{i=0}^{n}C_{n}^{i}i^{k}\). 我们根据套路\(n^{k}=\sum\limits_{i=0}^{k}C_{n}^{i}i!S_ ...

  7. python之面向对象进阶

    接口类 抽象类 钻石继承 多态 鸭子类型 接口类 接口类 继承有两种用途: 一:继承基类的方法,并且做出自己的改变或者扩展(代码重用) 二:声明某个子类兼容于某基类,定义一个接口类Interface, ...

  8. 使用hint优化Oracle的运行计划 以及 SQL Tune Advisor的使用

    背景: 某表忽然出现查询很缓慢的情况.cost 100+ 秒以上:严重影响生产. 原SQL: explain plan for select * from ( select ID id,RET_NO ...

  9. YOLO(5) YOLO2 代码讲解

    运行 darknet-rect2.exe detector demo F:/2Project/YOLO/yolo2/3data/TestData/data/voc.data F:/2Project/Y ...

  10. 20145203盖泽双 《网络对抗技术》实践八:Web基础

    20145203盖泽双 <网络对抗技术>实践八:Web基础 1.实践目标 (1)编写Web前端--含有表单的HTML代码. (2)编写Web前端--javascipt验证用户名.密码的代码 ...