2018-2019-1 20189206 《Linux内核原理与分析》第九周作业
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_switch和pick_next_task


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

从下向上每一层分别是 底层硬件 --> 内核实现 --> 系统调用接口 -->基础软件(shell 共享库等) --> 用户级的应用程序
**内核向上为用户系统调用提供接口,向下调用硬件服务接口。 **
2018-2019-1 20189206 《Linux内核原理与分析》第九周作业的更多相关文章
- 2019-2020-1 20199303<Linux内核原理与分析>第二周作业
2019-2020-1 20199303第二周作业 1.汇编与寄存器的学习 寄存器是中央处理器内的组成部份.寄存器是有限存贮容量的高速存贮部件,它们可用来暂存指令.数据和位址.在中央处理器的控制部件中 ...
- 20169219 linux内核原理与分析第二周作业
"linux内核分析"的第一讲主要讲了计算机的体系结构,和各寄存器之间对数据的处理过程. 通用寄存器 AX:累加器 BX:基地址寄存器 CX:计数寄存器 DX:数据寄存器 BP:堆 ...
- 2019-2020-1 20199314 <Linux内核原理与分析>第二周作业
1.基础学习内容 1.1 冯诺依曼体系结构 计算机由控制器.运算器.存储器.输入设备.输出设备五部分组成. 1.1.1 冯诺依曼计算机特点 (1)采用存储程序方式,指令和数据不加区别混合存储在同一个存 ...
- Linux内核原理与分析-第一周作业
本科期间,学校开设过linux相关的课程,当时的学习方式主要以课堂听授为主.虽然老师也提供了相关的学习教材跟参考材料,但是整体学下来感觉收获并不是太大,现在回想起来,主要还是由于自己课下没有及时动手实 ...
- 2019-2020-1 20199314 <Linux内核原理与分析>第一周作业
前言 本周对实验楼的Linux基础入门进行了学习,目前学习到实验九完成到挑战二. 学习和实验内容 快速学习了Linux系统的发展历程及其简介,学习了下的变量.用户权限管理.文件打包及压缩.常用命令的和 ...
- Linux内核原理与分析-第二周作业
写之前回看了一遍秒速五厘米:如果
- 2018-2019-1 20189221《Linux内核原理与分析》第一周作业
Linux内核原理与分析 - 第一周作业 实验1 Linux系统简介 Linux历史 1991 年 10 月,Linus Torvalds想在自己的电脑上运行UNIX,可是 UNIX 的商业版本非常昂 ...
- 2020-2021-1 20209307 《Linux内核原理与分析》第九周作业
这个作业属于哪个课程 <2020-2021-1Linux内核原理与分析)> 这个作业要求在哪里 <2020-2021-1Linux内核原理与分析第九周作业> 这个作业的目标 & ...
- 2019-2020-1 20199329《Linux内核原理与分析》第十三周作业
<Linux内核原理与分析>第十三周作业 一.本周内容概述 通过重现缓冲区溢出攻击来理解漏洞 二.本周学习内容 1.实验简介 注意:实验中命令在 xfce 终端中输入,前面有 $ 的内容为 ...
- 2019-2020-1 20199329《Linux内核原理与分析》第十二周作业
<Linux内核原理与分析>第十二周作业 一.本周内容概述: 通过编程理解 Set-UID 的运行机制与安全问题 完成实验楼上的<SET-UID程序漏洞实验> 二.本周学习内容 ...
随机推荐
- vue-cli创建第一个项目(用git bash解决上下键移动选择问题)
我电脑是windows:(nodejs已经有了) 1 下载vue-cli cmd 打开命令行,或者是gitbash.最好是用cnpm比较快. 2 创建项目: dos命令,cd 你的希望创建的文件夹 ...
- mybits根据表自动生成 java类和mapper 文件
mybits根据表自动生成 java类和mapper 文件 我这个脑子啊,每次创建新的工程都会忘记是怎么集成mybits怎么生成mapper文件的,so today , I can't write t ...
- shell 脚本的编写
创建一个shell文件 1. 创建一个.sh文件 2. 文件第一行声明shell编译器路径 #!/bin/bash 3. 修改文件权限 chmod 777 文件名 或 /bin/bash ...
- VS开发入门一:VS常用快捷键大全,工欲善其事必先利其器 只看标红的吧
1.快速using(这个的快捷键是ctrl+.)2.快速回到之前编辑的代码页面现在的项目动不动就几十个代码页面,经常需要在几个页面之间跳来跳去,这时就需要这两个快捷键:CTRL + - 向后定位,回到 ...
- 免费API 接口罗列,再也不愁没有服务器开发不了APP了(下)【申明:来源于网络】
免费API 接口罗列,再也不愁没有服务器开发不了APP了(下)[申明:来源于网络] 地址:http://mp.weixin.qq.com/s/QzZTIG-LHlGOrzfdvCVR1g
- 页面初始化document.body.clientWidth大小变化
目前:原因不明 初步判断:设置字体大小前图片加载失败! 结果:等待验证
- python-----编写接口,使用postman与soapiu与jemeter访问调用
实例:自己写一个注册接口 输入用户名.密码.验证码,当满足注册将密码进行md5加密. 场景 接口返回参数 提示 用户名存在 2000 exit 用户已存在 密码与验证码不相等 3000 wrong 密 ...
- day18:正则表达式和re模块
1,复习递归:返回值,不要只看到return就认为已经返回了,要看返回操作是在递归的第几层发生的,然后返回给了谁,如果不是返回给最外层函数,调用者就接收不到,需要再分析,看如何把结果返回回来,超过最大 ...
- xss脚本绕过限制的方法
第一关:第一关比较简单,直接写入标签就可以,这里不多说了,payload如下: http://sqler.win/xss/level1.php?name=test%3Csvg/onload=alert ...
- ajax中的同步与异步修改数据的问题
这次项目中因为前端有事儿,项目紧急加个新需求,于是自己硬着头皮上去看了下前端的逻辑后便开始动手了,但是为了简单起见就直接自己写了个ajax调服务来获取数据,然后修改前端定义的全局数据 //ajax来请 ...