linux内核分析学习笔记 ——第八章 进程的切换和系统的一般执行过程


学习目标:重点关注进程切换的过程,进程调度的时机,操作系统的基本构成以及一般的执行过程。

进程调度的时机

因为进程的调度只发生在内核中,进程调度函数schedule()只能在内核中被调用,用户进程无法调用。 因此,进程切换需要用到实现用户态到内核态的切换。

除了主动让出CPU外,进程的调度都需要在进程外进行。中断可以实现切出进程指令流的作用,中断处理程序是与进程无关的内核指令流。

硬中断与软中断

Intel定义的中断有以下几种:

  • 硬中断

    • CPU的两根引脚(可屏蔽中断和不可屏蔽中断)。CPU在执行每条指令后检测引脚的电平
    • 一般外设都是以这种方式与CPU进行信号传递
  • 软中断

    • 包括零错误、系统调用、调试断点等,在CPU执行指令过程中发生的各种特殊情况,称为异常。
    • 异常可以分为以下3种:
      • 故障 出现问题,但是可以恢复到当前指令
      • 退出 是不可恢复的严重故障,导致程序无法继续运行
      • 陷阱 程序主动产生的异常,在执行当前指令后发生。比如系统调用(int 0x80)等。

进程调度时机

schedule函数

linux内核通过schedule函数实现进程调度,schedule函数在运行队列中找到一个进程。把CPU分配给他。每调用一次schedule函数就实现一次进程调度,调用schedule函数就是进程调度的时机。

调用schedule函数的两种方式:

  • 进程主动调用schedule() 进程调用阻塞的系统调用等待外设或主动睡眠,最终会在内核中调用到schedule函数。
  • 松散调用,内核代码中可以随时调用schedule函数使当前内核路径让出CPU;也会根据need_resched标记做进程调度,内核检测到need_resched决定是否调用schedule函数。

上下文

CPU在任何时刻都处于以下3种情况之一:

  • 运行于用户空间,执行用户进程上下文。
  • 运行于内核空间,处于进程上下文。
  • 运行于内核空间,处于中断上下文。

中断上下文中的get_current可以获取一个指向当前进程的指针,指向被中断进程或即将运行的进程。硬件上下文切换信息也存储于该进程的内核堆栈中。

进程调度的时机

进程调度的时机就是内核调用schedule函数的时机。当内核即将返回用户空间时,内核会检查need_resched标志是否设置。如果设置,则调用schedule函数,将从中断处理程序返回用户空间的时间点作为一个固定的调度时机点

  • 用户进程通过特定的系统调用主动让出CPU
  • 中断处理程序在内核返回用户态时进行调度
  • 内核线程主动调用schedule函数让出CPU
  • 中断处理程序主动调用schedule函数让出CPU(包括以上两点)

调度策略与算法

  • 调度策略 根据算法的整体目标,是追求资源利用率最高还是追求相应及时或者其他目标,满足需要的目标就是调度策略
  • 调度算法 如何实现调度策略的方法并满足设定的目标

进程的分类

第一种分类方法

  • I/O消耗型进程 需要大量文件读写操作或者网络读写操作的进程。这一类进程的特点是CPU负载不高,大量时间都在等待读写数据
  • 处理器消耗型进程 这种进程CPU的占用率是100%,但没有太多的硬件进行读写操作。

第二种分类

  • 交互式进程 这类进程有大量的人机交互,进程不断地处于睡眠状态,等待用户输入
  • 批处理进程 不需要人机交互,在后台运行,但需要大量的系统资源
  • 实时进程 对调度延迟要求较高,这些进程往往执行非常重要的操作,要求立即相应并执行

调度策略

进程的分类

  • SCHED_FIFO 先进先出的实时进程,如果没有其它更高优先级的可运行实时进程,就可以一直使用cpu运行。对于这种进程,时间片长度是没有意义的。
  • SCHED_RR 时间片轮转的实时进程,所具有相同优先级(且都是当前情况下优先级最高)的SCHED_RR以时间片轮转的方式公平使用cpu。
  • SCHED_NORMAL 时间片轮转的普通进程,时间片用完之后变成过期进程,所有进程都成为过期进程之后,再统一把过期进程转变为活动进程。
    • 时间片轮转的普通进程(SCHED_NORMAL)优先级分为静态优先级和动态优先级。内核用从100(最高优先级)到139(最低优先级)表示普通进程的静态优先级。新进程总是继承父进程的静态优先级。

CFS调度算法 完全公平算法

  • 基本原理

    • 基于权重的动态优先级调度算法
    • 调度顺序由CPU的虚拟时间(vruntime)已使用的虚拟时间越少,进程排序就越靠前,进程再次被调度执行的概率更高。
  • 调度周期(_sched_period)

    • 某个时间周期内队列的所有进程都会至少被调度一次

         __sched_period = nr_running(进程数)*sysctl_sched_min_granularity(默认值)
  • 理论运行时间

      ideal_runtime = __sched_period * 进程权重/队列运行总权重
    
      每次可获取CPU后最长可占用时间为ideal_runtime
  • 虚拟运行时间

每个进程拥有一个vruntime,每次需要调度时就运行队列中拥有最小的vruntime的进程来运行,最长课运行时间为ideal_runtime

vruntime = 实际运行时间 * NICE_0_LOAD / 进程权重
= 实际运行时间 * 1024 / 进程权重 NICE_0_LOAD = 1024, 表示nice值为0的进程权重

可以看到, 进程权重越大, 运行同样的实际时间, vruntime增长的越慢

vruntime = 进程在一个调度周期内的实际运行时间 * 1024 / 进程权重
= (调度周期 * 进程权重 / 所有进程总权重) * 1024 / 进程权重
= 调度周期 * 1024 / 所有进程总权重

进程上下文的切换

内核需要有能力挂起正在CPU中运行的进程,并恢复执行以前挂起的进程,这个行为称为进程切换。进程切换中,挂起的CPU上执行的进程与中断时保存现场是不同的,中断前后在同一个进程上下文中只是用户态转向内核态。

进程上下文包含了:

  • 用户地址空间:进程代码、数据和用户堆栈等
  • 控制信息:进程描述符、内核堆栈
  • 硬件上下文:存储相关寄存器的值

实际代码中进程切换由两个步骤组成:

  • 切换页全局目录(RC3)以安装一个新的地址空间,这样不同的虚拟地址可以经过不同的页表转为不同的物理地址。
  • 切换内核态堆栈和硬件上下文

核心代码

进程切换的函数schedule()来选择一个新的进程来运行,并调用context_switch进行上下文的切换。在context_switch中最重要的是宏switch_to进行硬件上下文的切换。

以下是context_switch的关键代码

  • switch_mm表示将下一进程的页表地址装入RC3,得到物理地址
  • struct_mm是内存描述符,其中存储了进程地址空间中的所有信息

以下是汇编的switch_to代码

pushfl
pushl %ebp

注意,因为现在esp还在A的堆栈中,所以这两个东西被保存到A进程的内核堆栈中。

pushl %%ebp  当前堆栈的栈基址保存
movl %%esp, %[prev_sp] 保存当前堆栈的栈顶
movl %[next_sp],%%esp 将esp指向next进程的栈顶

从这个时候开始,CPU当前执行的进程已经是next进程了,因为esp已经指向next的内核堆栈。

上面三行汇编代码,实现的功能是完成内核堆栈的切换

movl $1f,%[prev_ip]
pushl %[next_ip]
jmp __switch_to

这三行代码使用到了next进程的内核堆栈,但实际上还是在prev内核堆栈上执行。

1:
popl %%ebp
popf1

这三行代码才是next进程开始执行的真正位置。

如果之前B也被switch_to出去过,那么[next_ip]里存的就是下面这个1f的标号,但如果进程B刚刚被创建,之前没有被switch_to出去过,那么[next_ip]里存的将是ret_ftom_fork。

这部分代码是内核代码,它们跟用户代码不在同一个代码段,所有进程在内核态共用这一段内核代码。这里涉及到的所有堆栈都是内核堆栈,而不涉及用户堆栈。

详细参考博客switch_to执行详解

进程调度的源码分析

首先还是冻结MenuOS,随后打开调试,分别设置断点。

gdb
file linux-3.18.6/vmlinux
target remote:1234
b schedule
b context_switch
b switch_to
b pick_next_task

开始执行后,可以看到,代码停在了schedule

之后可以看到context_switchpick_next_task

linux系统架构

linux操作系统的整体架构如图所示:

从下向上每一层分别是 底层硬件 --> 内核实现 --> 系统调用接口 -->基础软件(shell 共享库等) --> 用户级的应用程序

**内核向上为用户系统调用提供接口,向下调用硬件服务接口。 **

2018-2019-1 20189206 《Linux内核原理与分析》第九周作业的更多相关文章

  1. 2019-2020-1 20199303<Linux内核原理与分析>第二周作业

    2019-2020-1 20199303第二周作业 1.汇编与寄存器的学习 寄存器是中央处理器内的组成部份.寄存器是有限存贮容量的高速存贮部件,它们可用来暂存指令.数据和位址.在中央处理器的控制部件中 ...

  2. 20169219 linux内核原理与分析第二周作业

    "linux内核分析"的第一讲主要讲了计算机的体系结构,和各寄存器之间对数据的处理过程. 通用寄存器 AX:累加器 BX:基地址寄存器 CX:计数寄存器 DX:数据寄存器 BP:堆 ...

  3. 2019-2020-1 20199314 <Linux内核原理与分析>第二周作业

    1.基础学习内容 1.1 冯诺依曼体系结构 计算机由控制器.运算器.存储器.输入设备.输出设备五部分组成. 1.1.1 冯诺依曼计算机特点 (1)采用存储程序方式,指令和数据不加区别混合存储在同一个存 ...

  4. Linux内核原理与分析-第一周作业

    本科期间,学校开设过linux相关的课程,当时的学习方式主要以课堂听授为主.虽然老师也提供了相关的学习教材跟参考材料,但是整体学下来感觉收获并不是太大,现在回想起来,主要还是由于自己课下没有及时动手实 ...

  5. 2019-2020-1 20199314 <Linux内核原理与分析>第一周作业

    前言 本周对实验楼的Linux基础入门进行了学习,目前学习到实验九完成到挑战二. 学习和实验内容 快速学习了Linux系统的发展历程及其简介,学习了下的变量.用户权限管理.文件打包及压缩.常用命令的和 ...

  6. Linux内核原理与分析-第二周作业

    写之前回看了一遍秒速五厘米:如果

  7. 2018-2019-1 20189221《Linux内核原理与分析》第一周作业

    Linux内核原理与分析 - 第一周作业 实验1 Linux系统简介 Linux历史 1991 年 10 月,Linus Torvalds想在自己的电脑上运行UNIX,可是 UNIX 的商业版本非常昂 ...

  8. 2020-2021-1 20209307 《Linux内核原理与分析》第九周作业

    这个作业属于哪个课程 <2020-2021-1Linux内核原理与分析)> 这个作业要求在哪里 <2020-2021-1Linux内核原理与分析第九周作业> 这个作业的目标 & ...

  9. 2019-2020-1 20199329《Linux内核原理与分析》第十三周作业

    <Linux内核原理与分析>第十三周作业 一.本周内容概述 通过重现缓冲区溢出攻击来理解漏洞 二.本周学习内容 1.实验简介 注意:实验中命令在 xfce 终端中输入,前面有 $ 的内容为 ...

  10. 2019-2020-1 20199329《Linux内核原理与分析》第十二周作业

    <Linux内核原理与分析>第十二周作业 一.本周内容概述: 通过编程理解 Set-UID 的运行机制与安全问题 完成实验楼上的<SET-UID程序漏洞实验> 二.本周学习内容 ...

随机推荐

  1. [转]50个极好的bootstrap 后台框架主题下载

    50个极好的bootstrap 后台框架主题下载 http://sudasuta.com/bootstrap-admin-templates.html 越来越多的设计师和前端工程师开始用bootstr ...

  2. 深度学习入门之Mnist

    参看Deep learning from scratch,学习到反向传播网络后,把网络调通了,但是训练后损失函数减小,准确率没有变化,和瞎猜一样,是为什么呢?只有在看看各层缺少什么,关键是我的参数和书 ...

  3. 在php cli下可以使用 STDIN 来实现标准输入

    简单的例子:  echo "请输入一个数字:";  $num = trim(fgets(STDIN)); echo "请再输入一个数字:";  $num1 =  ...

  4. @media 媒体查询

    @media screen and (max-width: 300px) { //当视口宽度小于等于300px时生效 } max-width  相当于  <=  @media screen an ...

  5. 七牛免费SSL证书申请全流程

    购买证书 在七牛ssl 首页点击购买 购买限免证书 补全订单信息 免费证书,随意填写,问题不大 购买成功,查看订单详情,获取 TXT 值信息 添加 DNS TXT 验证 根据上一步,查看证书订单详情, ...

  6. getItemAt

    getItemAt(0) 获得第一行数据 getItemAt(1) 获得第二行数据

  7. CAutolock

    顾名思义CAutolock就是自动锁的意思,它可以把它之下的代码区锁住一直到其自身被释放掉    后这块代码区中的公共资源才会被其他线程使用.当然这个代码区能尽量少就尽量少,毕竟不能让其他线    程 ...

  8. MUI学习01-顶部导航栏

    建议:先看一下MUI注意事项 连接:http://ask.dcloud.net.cn/article/122 固定栏靠前 所谓的固定栏,也就是带有.mui-bar属性的节点,都是基于fixed定位的元 ...

  9. 03.Django的MTV开发模式详解和模型关系构建

    ORM:对象关系映射 一:MTV开发模式把数据存取逻辑.业务逻辑和表现逻辑组合在一起的概念有时被称为软件架构的 Model-View-Controller(MVC)模式. 在这个模式中,Model 代 ...

  10. mysql5.7.17安装配置图文教程

    My SQL的特点: MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品.MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,M ...