进程的切换和系统的一般执行过程

谈愈敏 原创作品转载请注明出处 《Linux内核分析》MOOC课程 http://mooc.study.163.com/course/USTC-1000029000

一、进程切换的关键代码switch_to分析

进程调度与进程调度的时机分析

不同类型的进程有不同的调度需求

第一种分类:

  • I/O-bound:频繁进行I/O,花费很长时间等待I/O
  • CPU-bound:计算密集型,需要大量CPU时间进行计算

第二种分类:

  • 批处理进程:不必交互、很快响应
  • 实时进程:要求响应时间短
  • 交互式进程(shell)

调度策略:是一组规则,它们决定什么时候以怎样的方式选择一个新进程运行。

  • Linux的进程根据优先级排队
  • Linux中进程的优先级是动态的

内核中的调度算法相关代码使用了类似OOD中的策略模式,把调度策略抽象掉,这些算法从实现的角度看仅仅是从运行队列中选择一个新进程,选择的过程中运用了不同的策略而已。进程的调度时机与进程的切换机制更为关键。

进程调度的时机:

  • 中断处理过程(包括时钟中断、I/O中断、系统调用和异常)中,直接调用schedule(),或者返回用户态时根据need_resched标记调用schedule();
  • 内核线程(只有内核态没有用户态的特殊进程)可以直接调用schedule()进行进程切换,也可以在中断处理过程中进行调度,也就是说内核线程作为一类的特殊的进程可以主动调度,也可以被动调度;
  • 用户态进程无法实现主动调度,只能被动调度,仅能通过陷入内核态后的某个时机点进行调度,即在中断处理过程中进行调度。

进程上下文切换相关代码分析

  • 为了控制进程的执行,内核必须有能力挂起正在CPU上执行的进程,并恢复以前挂起的某个进程的执行,这叫做进程切换、任务切换、上下文切换;
  • 挂起正在CPU上执行的进程,与中断时保存现场是不同的,中断前后是在同一个进程上下文中,只是由用户态转向内核态执行;
  • 进程上下文包含了进程执行需要的所有信息
    • 用户地址空间:包括程序代码,数据,用户堆栈等
    • 控制信息:进程描述符,内核堆栈等
    • 硬件上下文(注意中断也要保存硬件上下文只是保存的方法不同)
  • schedule()函数选择一个新的进程来运行,并调用context_switch进行上下文的切换,这个宏调用switch_to来进行关键上下文切换
    • next = pick_ next_task(rq, prev);//进程调度算法都封装这个函数内部
    • context_switch(rq, prev, next);//进程上下文切换
    • switch_to利用了prev和next两个参数:prev指向当前进程,next指向被调度的进程

schedule()中:

context_switch中:

switch_to中:

31#define switch_to(prev, next, last)
32do {
33 /*
34 * Context-switching clobbers all registers, so we clobber
35 * them explicitly, via unused output variables.
36 * (EAX and EBP is not listed because EBP is saved/restored
37 * explicitly for wchan access and EAX is the return value of
38 * __switch_to())
39 */
40 unsigned long ebx, ecx, edx, esi, edi;
41
42 asm volatile("pushfl\n\t" /* save flags */ //保存当前进程的flags
43 "pushl %%ebp\n\t" /* save EBP */ //把当前进程的堆栈基址压栈
44 "movl %%esp,%[prev_sp]\n\t" /* save ESP */ //把当前的栈顶保存到prev->thread.sp
45 "movl %[next_sp],%%esp\n\t" /* restore ESP */ //把下一个进程的栈顶保存到esp中,这两句完成了内核堆栈的切换
46 "movl $1f,%[prev_ip]\n\t" /* save EIP */ //保存当前进程的EIP,可以从这恢复
47 "pushl %[next_ip]\n\t" /* restore EIP */ //把下一个进程的起点位置压到堆栈,就是next进程的栈顶。next_ip一般是$1f,对于新创建的子进程是ret_from_fork
//一般用return直接把next_ip pop出来
48 __switch_canary
49 "jmp __switch_to\n" /* regparm call */ //jmp通过寄存器传递参数,即后面的a,d。 函数__switch_to也有return把next_ip pop出来
50 "1:\t" //认为从这开始执行next进程(EIP角度),第一条指令是next_ip这个起点,但前面已经完成内核堆栈的切换,早就是next进程的内核堆栈(算prev进程,比较模糊)
51 "popl %%ebp\n\t" /* restore EBP */ //next进程曾经是prev进程,压栈过ebp
52 "popfl\n" /* restore flags */
53
54 /* output parameters */
55 : [prev_sp] "=m" (prev->thread.sp), //当前进程的,在中断内部,在内核态,sp是内核堆栈的栈顶
56 [prev_ip] "=m" (prev->thread.ip), //当前进程的EIP
57 "=a" (last),
58
59 /* clobbered output registers: */
60 "=b" (ebx), "=c" (ecx), "=d" (edx),
61 "=S" (esi), "=D" (edi)
62
63 __switch_canary_oparam
64
65 /* input parameters: */
66 : [next_sp] "m" (next->thread.sp), //下一个进程的内核堆栈的栈顶
67 [next_ip] "m" (next->thread.ip), //下一个进程的执行起点
68
69 /* regparm parameters for __switch_to(): */
70 [prev] "a" (prev), //寄存器的传递
71 [next] "d" (next)
72
73 __switch_canary_iparam
74
75 : /* reloaded segment registers */
76 "memory");
77} while (0)

二、Linux系统的一般执行过程

Linux系统的一般执行过程分析

一般情况:当前系统正在进行,有一个用户态进程X,需要切换到用户态进程Y(进程策略决定):

  • 1、正在运行的用户态进程X
  • 2、发生中断——save cs:eip/esp/eflags(current) to kernel stack,then load cs:eip(entry of a specific ISR(中断服务例程的入口,对于系统调用就是system_call)) and ss:esp(point to kernel stack).//这些保存和加载都是CPU自动完成
  • 3、SAVE_ALL //保存现场
  • 4、中断处理过程中或中断返回前调用了schedule(),其中的switch_to做了关键的进程上下文切换
  • 5、标号1之后开始运行用户态进程Y(这里Y曾经通过以上步骤被切换出去过,就是next以前做过prev,因此可以从标号1继续执行)
  • 6、restore_all //Y进程从它的中断中恢复现场
  • 7、iret - pop cs:eip/ss:esp/eflags from kernel stack//从Y进程的内核堆栈中弹出
  • 8、继续运行用户态进程Y//执行发生中断时间点的下一条指令

关键:中断上下文的切换(中断和中断返回时CPU进行上下文切换)和进程上下文的切换(进程调度过程中,从一个进程的内核堆栈切换到另一个进程的内核堆栈)

Linux系统执行过程中的几个特殊情况

  • 通过中断处理过程中的调度时机,用户态进程与内核线程之间互相切换和内核线程之间互相切换,与最一般的情况非常类似,只是内核线程运行过程中发生中断没有进程用户态和内核态的转换;
  • 内核线程主动调用schedule(),只有进程上下文的切换,没有发生中断上下文的切换,与最一般的情况略简略;//用户态进程不能主动调用
  • fork:创建子进程的系统调用在子进程中的执行起点(next_ ip = ret_ from_ fork)返回用户态,进程返回不是从标号1开始执行,直接跳转到ret_ from_fork执行然后返回到用户态;
  • 加载一个新的可执行程序后返回到用户态的情况,如execve,只是中断上下文在execve系统调用内部被修改了;

三、Linux系统架构和执行过程概览

Linux操作系统架构概览

最简单也是最复杂的操作--执行ls命令

从CPU和内存的角度看Linux系统的执行

CPU执行指令的角度:

内存的角度:

实验

搭建环境:

cd LinuxKernel
rm menu -rf
git clone https://github.com/mengning/menu.git
cd menu
mv test_exec.c test.c
make rootfs

gdb调试

qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S

gdb
file ../linux-3.18.6/vmlinux
target remote:1234 设置断点:
b schedule
b pick_next_task
b context_switch
b switch_to

总结

进程调度算法只是一种抽象,着重理解进程的调度时机与进程的切换机制。

Linux系统的一般执行过程:当前系统正在进行,有一个用户态进程X,需要切换到用户态进程Y(进程策略决定)

内核使用的理解:32位x86系统下,每个进程的地址空间有4G,用户态0-3G,3G以上仅内核态可以访问,实际上所有进程3G以上是共享的,在内核中代码段,堆栈段都是相同的,回到用户态才不同。在内核态切换就比较容易了,所有进程都一样。进程进入内核就都一样,没有进程陷入内核就执行0号进程。内核可以看作各种中断处理过程和内核线程的集合。

20135220谈愈敏Blog8_进程的切换和系统的一般执行过程的更多相关文章

  1. 《Linux内核分析》第八周 进程的切换和系统的一般执行过程

    [刘蔚然 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000] WEEK EIGHT ...

  2. Linux内核设计第八周 ——进程的切换和系统的一般执行过程

    Linux内核设计第八周 ——进程的切换和系统的一般执行过程 第一部分 知识点总结 第二部分 实验部分 1.配置实验环境,确保menu内核可以正常启动 2.进入gdb调试,在shedule和conte ...

  3. LINUX内核分析第八周学习总结:进程的切换和系统的一般执行过程

    韩玉琪 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.进程切换的关 ...

  4. 20135202闫佳歆--week 8 进程的切换和系统的一般执行过程--学习笔记

    此为个人笔记存档 week 8 进程的切换和系统的一般执行过程 一.进程调度与进程切换 1.不同的进程有不同的调度需求 第一种分类: I/O密集型(I/O-bound) 频繁的进行I/O 通常会花费很 ...

  5. 《Linux内核分析》第八周学习小结 进程的切换和系统的一般执行过程

    进程的切换和系统的一般执行过程 一.进程调度的三个时机: 1.中断处理过程(包括时钟中断.I/O中断.系统调用和异常)中,直接调用schedule(),或者返回用户态时根据need_resched标记 ...

  6. Linux 第八周实验 进程的切换和系统的一般执行过程

    姬梦馨 原创作品 <Linux内核分析>MOOC课程:http://mooc.study.163.com/course/USTC-1000029000 第八讲 进程的切换和系统的一般执行过 ...

  7. Linux内核分析——进程的切换和系统的一般执行过程

    进程的切换和系统的一般执行过程 一.进程切换的关键代码switch_to分析 (一)进程调度与进程调度的时机分析 1.不同类型的进程有不同的调度需求 第一种分类: (1)I/O-bound:频繁进行I ...

  8. LINUX内核分析第八周总结:进程的切换和系统的一般执行过程

    一.进程调度与进程切换 1.不同的进程有不同的调度需求 第一种分类: I/O密集型(I/O-bound) 频繁的进行I/O 通常会花费很多时间等待I/O操作的完成 CPU密集型(CPU-bound) ...

  9. LINUX内核分析第八周学习总结——进程的切换和系统的一般执行过程

    LINUX内核分析第八周学习总结——进程的切换和系统的一般执行过程 张忻(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163.com/c ...

随机推荐

  1. Effective Java 39 Make defensive copies when needed

    Principle It is essential to make a defensive copy of each mutable parameter to the constructor. Def ...

  2. Effective Java 55 Optimize judiciously

    Principle Strive to write good programs rather than fast ones. Strive to avoid design decisions that ...

  3. ERP产品价格成本计算的几个方法(转)

          一般财务计算产品价格又很多方法,我这里做了几个供参考,实体属性主要是编号.数量.价格等,这里就不列出了. /// <summary> /// 先进先出算法 /// </s ...

  4. Eclipse 快捷键 篇

    1. Ctrl+Shift+R:打开资源这可能是所有快捷键组合中最省时间的了.这组快捷键可以让你打开你的工作区中任何一个文件,而你只需要按下文件名或mask名中的前几个字母,比如applic*.xml ...

  5. JavaScript 题目破解过程与解析

    题目来源 https://www.hackthissite.org/missions/javascript/ HackThisSite JavaScript mission 1-7 1 我先尝试输入  ...

  6. Unity3d内置浏览器

    uWebKit是一个Unity3d插件,个人认为比较强大,值得收藏啊 有图有真相: 安装以及破解说明: 1.导入资源包 2.将破解目录里的Editor复制到工程项目的Assets目录下进行覆盖 3.打 ...

  7. 初始化 Ubuntu Trusty 14.04

    1. 软件源 sudo vim /etc/apt/source.list # 将软件源改为 sohu 的 deb http://mirrors.sohu.com/ubuntu/ trusty main ...

  8. [Editor]Unity Editor类常用方法

    Editor文档资料 Unity教程之-Unity Attribute的使用总结:http://www.unity.5helpyou.com/3550.html 利用unity3d属性来设置Inspe ...

  9. box unboxing(装箱 拆箱) C#编程指南

    box(装箱)消耗大 box在堆栈中创建一个新的对象,性能消耗大 int i = 123; // Boxing copies the value of i into object o. object ...

  10. [转]Source Insight使用小技巧小结

    Source Insight是一款强大的代码查看工具,本身支持扩展性很好.下面我们就介绍2个扩展用例. 1.快速打开当前文件所在的目录,这个功能类似于eclipse的easyshell插件,就是能快速 ...