理解进程调度时机跟踪分析进程调度与进程切换的过程

一、基础知识

Linux系统的一般执行过程

一般情况:正在运行的用户态进程X切换到运行用户态进程Y的过程

1. 正在运行的用户态进程X

2. 发生中断

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

几种特殊情况

  • 通过中断处理过程中的调度时机,用户态进程与内核线程之间互相切换和内核线程之间互相切换,与最一般的情况非常类似,只是内核线程运行过程中发生中断没有进程用户态和内核态的转换;

  • 内核线程主动调用schedule(),只有进程上下文的切换,没有发生中断上下文的切换,与最一般的情况略简略;

  • 创建子进程的系统调用在子进程中的执行起点及返回用户态,如fork;

  • 加载一个新的可执行程序后返回到用户态的情况,如execve;

进程的调度时机与进程的切换

  • 操作系统原理中介绍了大量进程调度算法,这些算法从实现的角度看仅仅是从运行队列中选择一个新进程,选择的过程中运用了不同的策略而已。

  • 对于理解操作系统的工作机制,反而是进程的调度时机与进程的切换机制更为关键。

进程调度的时机

  • 中断处理过程(包括时钟中断、I/O中断、系统调用和异常)中,直接调用schedule(),或者返回用户态时根据need_resched标记调用schedule();比如sleep,就可能直接调用了schedule

  • 内核线程可以直接调用schedule()进行进程切换,也可以在中断处理过程中进行调度,也就是说内核线程作为一类的特殊的进程可以主动调度,也可以被动调度;

  • 用户态进程无法实现主动调度,仅能通过陷入内核态后的某个时机点进行调度,即在中断处理过程中进行调度。用户态进程只能被动调度。

进程的切换

  • 为了控制进程的执行,内核必须有能力挂起正在CPU上执行的进程,并恢复以前挂起的某个进程的执行,这叫做进程切换、任务切换、上下文切换;即进程上下文切换!

  • 挂起正在CPU上执行的进程,与中断时保存现场是不同的,中断前后是在同一个进程上下文中,只是由用户态转向内核态执行;

  • 进程上下文包含了进程执行需要的所有信息

    • 用户地址空间:包括程序代码,数据,用户堆栈等

    • 控制信息:进程描述符,内核堆栈等

    • 硬件上下文(注意中断也要保存硬件上下文只是保存的方法不同)

二、实验内容

代码分析

   #define switch_to(prev, next, last)
do {
/*
* Context-switching clobbers all registers, so we clobber
* them explicitly, via unused output variables.
* (EAX and EBP is not listed because EBP is saved/restored
* explicitly for wchan access and EAX is the return value of
* __switch_to())
*/
unsigned long ebx, ecx, edx, esi, edi;
asm volatile("pushfl\n\t" /* 保存当前进程flags */
"pushl %%ebp\n\t" /* 当前进程堆栈基址压栈*/
"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进程的栈顶为起点*/ //完成EIP的切换
__switch_canary
//next_ip一般是$1f,对于新创建的子进程时ret_from_fork
"jmp __switch_to\n" /*prev进程中,设置next进程堆栈*/
//jmp不同于call是通过寄存器传递参数
"1:\t" //next进程开始执行
"popl %%ebp\n\t"
"popfl\n" /*输出变量定义*/
: [prev_sp] "=m" (prev->thread.sp), //[prev_sp]定义内核堆栈栈顶
[prev_ip] "=m" (prev->thread.ip), //[prev_ip]当前进程EIP
"=a" (last), /* 要破坏的寄存器: */
"=b" (ebx), "=c" (ecx), "=d" (edx),
"=S" (esi), "=D" (edi) __switch_canary_oparam /* 输入变量: */
: [next_sp] "m" (next->thread.sp), //[next_sp]下一个内核堆栈栈顶
[next_ip] "m" (next->thread.ip),
//[next_ip]下一个进程执行起点,,一般是$1f,对于新创建的子进程是ret_from_fork /* regparm parameters for __switch_to(): */
[prev] "a" (prev),
[next] "d" (next) __switch_canary_iparam : /* 重新加载段寄存器 */
"memory");
} while (0)

三、总结

   通过学习,了解到Linux使用了堆栈进行了进程调度。内核在调用schedule()在需要的时候重新启用内核抢占、并检查是否一些其他的进程已经设置了当前进程的

tlf_need_resched标志,如果是,整个schedule()函数重新开始执行,否则,函数结束。linux调度的核心函数为schedule,schedule函数封装了内核调度的框架。

细节实现上调用具体的调度类中的函数实现。当切换进程已经选好后,就开始用户虚拟空间的处理,然后就是进程的切换switch_to()。所谓进程的切换主要就是堆栈

的切换,这是由宏操作switch_to()完成的。

Linux内核分析第九次作业的更多相关文章

  1. 20135327郭皓--Linux内核分析第九周 期中总结

    Linux内核分析第九周 期中总结 一.知识概要 1. 计算机是如何工作的 存储程序计算机工作模型:冯诺依曼体系结构 X86汇编基础 会变一个简单的C程序分析其汇编指令执行过程 2. 操作系统是如何工 ...

  2. Linux内核启动分析过程-《Linux内核分析》week3作业

    环境搭建 环境的搭建参考课件,主要就是编译内核源码和生成镜像 start_kernel 从start_kernel开始,才真正进入了Linux内核的启动过程.我们可以把start_kernel看做平时 ...

  3. 分析Linux内核中进程的调度(时间片轮转)-《Linux内核分析》Week2作业

    1.环境的搭建: 这个可以参考孟宁老师的github:mykernel,这里不再进行赘述.主要是就是下载Linux3.9的代码,然后安装孟宁老师编写的patch,最后进行编译. 2.代码的解读 课上的 ...

  4. 分析一个C语言程序生成的汇编代码-《Linux内核分析》Week1作业

    署名信息 郭春阳 原创作品转载请注明出处 :<Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 C源码 这 ...

  5. Linux内核分析第二次作业

    这周学习了<庖丁解牛Linux内核分析>并且学习了实验楼的相关知识. 在实验楼的虚拟环境下编写代码: 通过gcc编译后,使用查看文件命令:cat  -n 20189223.c 在vim中, ...

  6. 《Linux内核分析》 week8作业-Linux加载和启动一个可执行程序

    一.ELF文件格式 ELF(Executable and Linking Format)是x86 Linux系统下常用的目标文件格式,有三种主要类型: 适于连接的可重定位文件,可与其他目标文件一起创建 ...

  7. 《Linux内核分析》 week6作业-Linux内核fork()系统调用的创建过程

    一.进程控制块PCB-stack_struct 进程在操作系统中都有一个结构,用于表示这个进程.这就是进程控制块(PCB),在Linux中具体实现是task_struct数据结构,它主要记录了以下信息 ...

  8. 《Linux内核分析》 week5作业-system call中断处理过程

    一.使用gdb跟踪分析一个系统调用内核函数 1.在test.c文件中添加time函数与采用c语言内嵌汇编的time函数.具体实现请看下图. 2.然后在main函数中添加MenuConfig函数,进行注 ...

  9. 《Linux内核分析》 week4作业-使用嵌入式汇编调用一个系统调用

    一.fork的嵌入式汇编执行 #include <stdio.h> #include <unistd.h> int main(){ pid_t pid; asm volatil ...

随机推荐

  1. C/C++.判断文件是否存在(_access)

    1. int _access(char* path,int mode)头文件<io.h>功能:确定文件或文件夹的访问权限.如果指定的存取方式有效,则函数返回0,否则函数返回-1. 参数pa ...

  2. ubuntu 关闭 笔记本键盘背景灯

    /etc/rc.local 加入 ' > /sys/class/leds/tpacpi::kbd_backlight/brightness

  3. 【分布式搜索引擎】Elasticsearch写入和读取数据过程

    一.Elasticsearch写人数据的过程 1)客户端选择一个node发送请求过去,这个node就是coordinating node(协调节点)2)coordinating node,对docum ...

  4. 『高性能模型』深度可分离卷积和MobileNet_v1

    论文原址:MobileNets v1 TensorFlow实现:mobilenet_v1.py TensorFlow预训练模型:mobilenet_v1.md 一.深度可分离卷积 标准的卷积过程可以看 ...

  5. javaScript_Demo 全选和反选单选框

    进行单选的全选和反选 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> &l ...

  6. QANet

    Reading Comprehension(RC) 阅读理解对于机器来说, 是一项非常艰巨的任务.google提出QANet, 目前(2018 0505)一直是SQuAD的No. 1. 今天简单地与大 ...

  7. protobuf example make backup

    # See README.txt. .PHONY: all cpp java python clean all: cpp #java python cpp: add_person_cpp list_p ...

  8. JAVA8之函数式接口

    由于JDK8已经发布一段时间了,也开始逐渐稳定,未来使用JAVA语言开发的系统会逐渐升级到JDK8,因为为了以后工作需要,我们有必要了解JAVA8的一些新的特性.JAVA8相对JAVA7最重要的一个突 ...

  9. asp.net 网页跳转的几种常用方法

    Response.Redirect("http://www.baidu.com",false); 后面的bool值为是否停止执行当前页.跳转向新的页面,原窗口被代替.浏览器中的UR ...

  10. 自动化测试-15.selenium单选框与复选框状态判断

    本篇主要介绍单选框和复选框的操作 一.认识单选框和复选框 1.先认清楚单选框和复选框长什么样 2.各位小伙伴看清楚哦,上面的单选框是圆的:下图复选框是方的,这个是业界的标准,要是开发小伙伴把图标弄错了 ...