2019-2020-1 20199308《Linux内核原理与分析》第九周作业
《Linux内核分析》
第八章 可执行程序工作原理进程的切换和系统的一般执行过程
8.1 知识点
进程调度的时机
- ntel定义的中断类型主要有以下几种
- 硬中断(Interrupt)
- 软中断/异常(Exception)
- 故障(Fault)
- 退出(Abort)
- 陷阱(Trap)
- schedule()函数选择一个新的进程来运行,并调用context_switch进行上下文的切换,这个宏调用switch_to来进行关键上下文切换
- next = pick_next_task(rq, prev);//进程调度算法都封装这个函数内部
- context_switch(rq, prev, next);//进程上下文切换
- switch_to利用了prev和next两个参数:prev指向当前进程,next指向被调度的进程
- Linux系统的一般执行过程
- 最一般的情况:正在运行的用户态进程X切换到运行用户态进程Y的过程
- 1.正在运行的用户态进程X
- 2.发生中断——save cs:eip/esp/eflags(current) to kernel stack,then load cs:eip(entry of a specific ISR) and ss:esp(point to kernel stack).
- 3.SAVE_ALL //保存现场
- 4.中断处理过程中或中断返回前调用了schedule(),其中的switch_to做了关键的进程上下文切换
- 5.标号1之后开始运行用户态进程Y(这里Y曾经通过以上步骤被切换出去过因此可以从标号1继续执行)
- 6.restore_all //恢复现场
- 7.iret - pop cs:eip/ss:esp/eflags from kernel stack
- 8.继续运行用户态进程Y
- 最一般的情况:正在运行的用户态进程X切换到运行用户态进程Y的过程
- 几种特殊情况
- 通过中断处理过程中的调度时机,用户态进程与内核线程之间互相切换和内核线程之间互相切换,与最一般的情况非常类似,只是内核线程运行过程中发生中断没有进程用户态和内核态的转换;
- 内核线程主动调用schedule(),只有进程上下文的切换,没有发生中断上下文的切换,与最一般的情况略简略;
- 创建子进程的系统调用在子进程中的执行起点及返回用户态,如fork;
- 加载一个新的可执行程序后返回到用户态的情况,如execve;
- ch_to利用了prev和next两个参数:prev指向当前进程,next指向被调度的进程


8.2 核心代码分析
context_switch代码
static inline void context_switch(struct rq *rq, struct task_struct *prev, struct task_struct *next)
{
struct mm_struct *mm, *oldmm;
prepare_task_switch(rq, prev, next);
mm = next->mm;
oldmm = prev->active_mm;
/*
* For paravirt, this is coupled with an exit in switch_to to
* combine the page table reload and the switch backend into
* one hypercall.
*/
arch_start_context_switch(prev);
if (!mm) { //如果被切换进来的进程的mm为空切换,内核线程mm为空
next->active_mm = oldmm; //将共享切换出去的进程的active_mm
atomic_inc(&oldmm->mm_count); //有一个进程共享,所有引用计数加一
enter_lazy_tlb(oldmm, next); //普通mm不为空,则调用switch_mm切换地址空间
} else
switch_mm(oldmm, mm, next);
if (!prev->mm) {
prev->active_mm = NULL;
rq->prev_mm = oldmm;
}
/*
* Since the runqueue lock will be released by the next
* task (which is an invalid locking op but in the case
* of the scheduler it's an obvious special-case), so we
* do an early lockdep release here:
*/
spin_release(&rq->lock.dep_map, 1, _THIS_IP_);
context_tracking_task_switch(prev, next);
// 这里切换寄存器状态和栈
switch_to(prev, next, prev);
barrier();
/*
* this_rq must be evaluated again because prev may have moved
* CPUs since it called schedule(), thus the 'rq' on its stack
* frame will be invalid.
*/
finish_task_switch(this_rq(), prev);
}
switch_to代码
#define switch_to(prev, next, last) //prev指向当前进程,next指向被调度的进程
do {
unsigned long ebx, ecx, edx, esi, edi;
asm volatile("pushfl\n\t" //把prev进程的flag保存到prev进程的内核堆栈中
"pushl %%ebp\n\t" //把prev进程的基址ebp保存到prev进程的内核堆栈中
"movl %%esp,%[prev_sp]\n\t"//保存ESP
"movl %[next_sp],%%esp\n\t"//更新ESP,将下一栈顶保存到ESP中
"movl $1f,%[prev_ip]\n\t"//保存当前进程EIP*
"pushl %[next_ip]\n\t"//把next进程起点压入next进程的内核堆栈栈顶
__switch_canary
"jmp __switch_to\n"//prev进程中设置next进程堆栈
//jmp不同于call,是通过寄存器传递参数,而不是通过堆栈传递参数,所以ret时弹出的是之前压入栈顶的next进程起点
//wancheng EIP的切换
"1:\t"
"popl %%ebp\n\t"
"popfl\n"
/* output parameters */
: [prev_sp] "=m"(prev->thread.sp), //保存prev进程的esp
[prev_ip] "=m"(prev->thread.ip), //保存prev进程的eip
"=a" (last),
/* clobbered output registers: */
"=b" (ebx), "=c"(ecx), "=d" (edx),
"=S" (esi), "=D"(edi)
__switch_canary_oparam
/* input parameters: */
: [next_sp] "m" (next->thread.sp), //next进程内核堆栈栈顶地址,即esp
[next_ip] "m" (next->thread.ip), //next进程的原eip
/* regparm parameters for __switch_to():*/
//jmp通过eax寄存器和edx寄存器传递参数
[prev] "a" (prev),
[next] "d" (next)
__switch_canary_iparam
: /* 重新加载段寄存器
"memory");
} while (0)
8.3 实验
克隆menu,编译内核,启动gdb




在schedule(),context_switch(),pick_next_task()打入断点

按c执行,停在schedule函数处

按c继续执行到pick_next_task断点处

按c继续执行到context_switch断点处,用来实现进程的切换。

总结
一次一般的进程切换过程,其中必须完成的关键操作是:切换地址空间、切换内核堆栈、切换内核控制流程,加上一些必要的寄存器保存和恢复。这里,除去地址空间的切换,其他操作要强调“内核”一词。这是因为,这些操作并非针对用户代码,切换完成后,也没有立即跑到next的用户空间中执行。用户上下文的保存和恢复是通过中断和异常机制,在内核态和用户态相互切换时才发生的。schedule()是内核和其他部分用于调用进程调度器的入口,选择哪个进程可以运行,何时将其投入运行。就如switch_to中的方法,通过压栈出栈交换prev_ip和next_ip。然后返回,从而完成进程调度。而用哪个作为下来的进程,则通过优先级的算法和进程调度算法来决定。
2019-2020-1 20199308《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程序漏洞实验> 二.本周学习内容 ...
随机推荐
- 图解JVM类加载机制和双亲委派模型
我们都知道以 .java 结尾的 Java 源文件,经过编译之后会变成 .class 结尾的字节码文件.JVM 通过类加载器来加载字节码文件,然后再执行程序. 什么时候加载一个类 那么,什么时候类加载 ...
- extend()和append()的区别
append()方法用于在列表末尾添加新的对象(对象可以是值或列表),一般用于添加列表项. extend()方法用于在列表末尾追加另一个序列中的多个值.
- Html,Css遇到的bug2020031601
td,里面jquery设置height,设置成功也没有效果. div可以成功设置,并产生效果. 可能是td,div有一些隐藏的特性不同导致的.
- springboot + aop + Lua分布式限流的最佳实践
整理了一些Java方面的架构.面试资料(微服务.集群.分布式.中间件等),有需要的小伙伴可以关注公众号[程序员内点事],无套路自行领取 一.什么是限流?为什么要限流? 不知道大家有没有做过帝都的地铁, ...
- 直播回顾 | IOT、AI、云计算等融合技术推进制造业产业转型(二)
3月31日,BoCloud博云.京东智联云.海尔集团联手,以“制造”到“智造”为主题,进行了IT赋能企业数字化转型实践分享. 博云售前解决方案架构师尹贺杰,京东云与AI企业云业务部高级业务技术经理吴世 ...
- Altium 分形天线设计
Altium 分形天线设计 程序运行界面 Cantor三分集 Koch雪花 Sierpinski垫片 源代码: Iter_Num = 4 'diedai PI = 3.1415926 Call ...
- 安装部署Tomcat服务器
安装部署Tomcat服务器 案例1:安装部署Tomcat服务器 案例2:使用Tomcat部署虚拟主机 案例3:使用Varnish加速Web 1案例1:安装部署Tom ...
- 二维码,QR码,编码原理与实现
文章更新于:2020-02-18 注:开头是四篇文章的链接,下面是这四篇文章的截图 # 想了解二维码,读这几篇就够了 # 二维码的基础原理是什么 https://cli.im/news/help/10 ...
- 模板继承和UImodul 和 UImethods
模板继承和UImodul 和 UImethods 模板的继承 {% extends path %} path为templates下的相对路径 {% block block_name %}conten ...
- GhostNet: 使用简单的线性变换生成特征图,超越MobileNetV3的轻量级网络 | CVPR 2020
为了减少神经网络的计算消耗,论文提出Ghost模块来构建高效的网络结果.该模块将原始的卷积层分成两部分,先使用更少的卷积核来生成少量内在特征图,然后通过简单的线性变化操作来进一步高效地生成ghost特 ...