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

(一)进程调度与进程调度的时机分析

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

  • 第一种分类:

    • I/O-bound:频繁地进行I/O,花费很多的时间等待I/O操作的完成
    • CPU-bound:计算密集型,需要大量的CPU时间进行计算
  1. 第二种分类:
    • 批处理进程
    • 实时进程
    • 交互式进程(shell)
  2. 进程调度策略:是一组规则,决定何时以何种方式选择进程。
  • Linux的调度基于分时和优先级策略:
    1. 进程根据优先级排队;
    2. 这个优先级的值表示如何适当分配CPU;
    3. 进程的优先级是动态的
    4. 调度程序会根据进程的运行周期动态调整优先级;
    5. 比如nice等系统调用,可以手动调整优先级
  • 调度策略本质上是一种算法,这些算法从实现的角度看仅仅是从运行队列中选择一个新进程,选择的过程中运用了不同的策略而已
  • 内核中的调度算法相关代码使用了类似OOD中的策略模式

3.进程调度的时机

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

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

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

(二)进程切换上下文的相关代码

1.进程的切换

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

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

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

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

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

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

  • schedule()函数选择一个新的进程来运行,并调用context_switch进行上下文的切换,这个宏调用switch_to来进行关键上下文切换

switch_to利用了prev和next两个参数:prev指向当前进程,next指向被调度的进程

  1. 31#define switch_to(prev, next, last)                    \
  2. 32do {                                 \
  3. 33  /*                              \
  4. 34   * Context-switching clobbers all registers, so we clobber  \
  5. 35   * them explicitly, via unused output variables.     \
  6. 36   * (EAX and EBP is not listed because EBP is saved/restored  \
  7. 37   * explicitly for wchan access and EAX is the return value of   \
  8. 38   * __switch_to())                     \
  9. 39   */                                \
  10. 40  unsigned long ebx, ecx, edx, esi, edi;                \
  11. 41                                  \
  12. 42  asm volatile("pushfl\n\t"      /* save    flags */   \
  13. 43           "pushl %%ebp\n\t"        /* save    EBP   */ \
  14. 44           "movl %%esp,%[prev_sp]\n\t"  /* save    ESP   */ \
  15. 45           "movl %[next_sp],%%esp\n\t"  /* restore ESP   */ \
  16. 46           "movl $1f,%[prev_ip]\n\t"    /* save    EIP   */ \
  17. 47           "pushl %[next_ip]\n\t"   /* restore EIP   */    \
  18. 48           __switch_canary                   \
  19. 49           "jmp __switch_to\n"  /* regparm call  */ \
  20. 50           "1:\t"                        \
  21. 51           "popl %%ebp\n\t"     /* restore EBP   */    \
  22. 52           "popfl\n"         /* restore flags */  \
  23. 53                                  \
  24. 54           /* output parameters */                \
  25. 55           : [prev_sp] "=m" (prev->thread.sp),     \
  26. 56             [prev_ip] "=m" (prev->thread.ip),        \
  27. 57             "=a" (last),                 \
  28. 58                                  \
  29. 59             /* clobbered output registers: */     \
  30. 60             "=b" (ebx), "=c" (ecx), "=d" (edx),      \
  31. 61             "=S" (esi), "=D" (edi)             \
  32. 62                                       \
  33. 63             __switch_canary_oparam                \
  34. 64                                  \
  35. 65             /* input parameters: */                \
  36. 66           : [next_sp]  "m" (next->thread.sp),        \
  37. 67             [next_ip]  "m" (next->thread.ip),       \
  38. 68                                       \
  39. 69             /* regparm parameters for __switch_to(): */  \
  40. 70             [prev]     "a" (prev),              \
  41. 71             [next]     "d" (next)               \
  42. 72                                  \
  43. 73             __switch_canary_iparam                \
  44. 74                                  \
  45. 75           : /* reloaded segment registers */           \
  46. 76          "memory");                  \
  47. 77} while (0)

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

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

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

 

  • 正在运行的用户态进程X

  • 发生中断——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).

  • SAVE_ALL //保存现场

  • 中断处理过程中或中断返回前调用了schedule(),其中的switch_to做了关键的进程上下文切换

  • 标号1之后开始运行用户态进程Y(这里Y曾经通过以上步骤被切换出去过因此可以从标号1继续执行)

  • restore_all //恢复现场
  • iret - pop cs:eip/ss:esp/eflags from kernel stack

  • 继续运行用户态进程Y

  • 中断上下文和进程上下文切换:前者是CPU内部的切换;后者是在内核中堆栈的切换

 

(三)几种特殊情况

 

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

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

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

    4. 加载一个新的可执行程序后返回到用户态的情况,如execve;4.地址切换

(四)内核与舞女

  1. 进程的地址空间一共有4G,其中0——3G是用户态可以访问,3G以上只有内核态可以访问
  2. 内核就是各种中断处理过程和内核线程的集合;
  3. 内核相当于出租车,可以为每一个“招手”的进程提供内核态到用户态的转换;
  4. 没有进程需要“承载”的时候,内核进入idle0号进程进行“空转”;
  5. 3G以上的部分就是这样的“出租车”,是所有进程共享的,在内核态部分切换的时候就比较容易

三、LINUX 系统架构和执行过程概述

(一)Linux系统架构概览

(二)最简单也是最复杂的操作——ls

COW :COPY ON WRITE

(三)CPU和内存的角度看Linux系统的执行

  1. 执行gets()函数;
  2. 执行系统调用,陷入内核;
  3. 等待输入,CPU会调度其他进程执行,同时wait一个I/O中断;
  4. 敲击ls,发I/O中断给CPU,中断处理程序进行现场保存、压栈等等;
  5. 中断处理程序发现X进程在等待这个I/O(此时X已经变成阻塞态),处理程序将X设置为WAKE_UP;
  6. 进程管理可能会把进程X设置为next进程,这样gets系统调用获得数据,再返回用户态堆栈

  • 从内存角度看,所有的物理地址都会被映射到3G以上的地址空间:因为这部分对所有进程来说都是共享的

四、实验

1、配置实验环境,确保menu内核可以正常启动

2.进入gdb调试,在shedule和context_switch处设置断点

4.c之后按n单步执行,直到遇到__schedule函数

Linux内核分析 笔记八 进程的切换和系统的一般执行过程 ——by王玥的更多相关文章

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

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

  2. 20135327郭皓--Linux内核分析第八周 进程的切换和系统的一般执行过程

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

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

    Linux内核分析第八周--进程的切换和系统的一般执行过程 李雪琦+原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/cou ...

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

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

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

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

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

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

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

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

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

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

  9. 20135239 益西拉姆 linux内核分析 进程的切换和系统的一般执行过程

    week 8 进程的切换和系统的一般执行过程 [ 20135239 原文请转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course ...

随机推荐

  1. javascript闭包—围观大神如何解释闭包

    闭包的概念已经出来很长时间了,网上资源一大把,本着拿来主意的方法来看看. 这一篇文章 学习Javascript闭包(Closure) 是大神阮一峰的博文,作者循序渐进,讲的很透彻.下面一一剖析. 1. ...

  2. Leviticus

    The head is empty and empty. Just practicing English will not have any effect. The best effect is to ...

  3. python五十八课——正则表达式(分组)

    演示正则中的替换和切割操作:在这之前我们先学习一个分组的概念: 分组:在正则中定义(...)就可以进行分组,理解为得到了一个子组好处:1).如果正则中的逻辑比较复杂,使用分组就可以优化代码的阅读性(更 ...

  4. lij IDEA项目包分层结构显示设置

    使用Intellij IDEA创建项目发现包没有分层,使用不方便. 可以点击右上角的设置,把红框选项的√去掉即可. 就会分层显示了,这就很舒服了.

  5. Arduino IDE for ESP8266 ()组网

    多个esp8266连接在同一个 WIFI上,在局域网内部,相互传数据 #include <ESP8266WiFi.h> #define led 2 //发光二极管连接在8266的GPIO2 ...

  6. CentOS 7.X 系统安装及优化

    centos的演变 启动流程sysvinit 串行启动:一次一个,一个一个启动 并行启动:全部的一起启动 init优点 运行非常良好.主要依赖于shell脚本 init缺点 1.启动慢 2.容易夯住, ...

  7. Shell逻辑语句

    case esac 语句 参考 :https://blog.csdn.net/wu20093346/article/details/47210809 case ... esac 与其他语言中的 swi ...

  8. node.js如何将远程的文件下载到本地、解压、读取

    其实要解决的问题,很简单,获取远程文件,然后解压到本地读取. 在vscode中通过node.js来实现是比较方便的,相比之前的zip.js,我觉得我还是比较喜欢node.js实现方式. test.js ...

  9. Dubbo高级篇4

    https://blog.csdn.net/moonpure/article/details/52842115 线程模型 http://dubbo.io/User+Guide-zh.htm 用户指南& ...

  10. 原生js函数的伪重载

    一.我们在学习java的时候,其中方法有一个比较的重要的特性重载,根据传入的参数的个数来执行不同的方法,而方法其根据签名来判断,而JavaScript却不能根据方法的签名来进行重载,只能通过参数的个数 ...