网易云课堂 Linux内核分析(八)
来源:互联网 发布:程序员必备软件 编辑:程序博客网 时间:2024/04/30 05:06
寇亚飞 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
理解进程调度时机跟踪分析进程调度与进程切换的过程
进程调度的基本概念
操作系统中进程的调度是非常常见的一种状态,无论采用何种调度册策略,它都是从进程队列中选择了一个新进程而已。因此,掌握进程调度的时机与进程上下文的切换非常重要。
进程调度时机
中断处理过程(包括时钟中断、I/O 中断、系统调用和异常)中,直接调用schedule,或者返回用户态时根据 need_resched 标记调用 schedule
内核线程可以直接调用 schedule 进行进程切换,也可以在中断处理过程中进行调度,也就是说内核线程作为一类的特殊的进程可以主动调度,也可以被动调度
用户态进程无法实现主动调度,仅能通过陷入内核态后的某个时机点进行调度,即在中断处理过程中进行调度
进程切换
为了控制进程的执行,内核必须有能力挂起正在 CPU 上执行的进程,并恢复以前挂起的某个进程的执行的过程,叫做进程切换、任务切换、上下文切换。挂起正在 CPU 上执行的进程,与中断时保存现场是有区别的,中断前后是在同一个进程上下文中,只是由用户态转向内核态执行。
进程上下文包含了进程执行需要的所有信息。
- 用户地址空间:包括程序代码,数据,用户堆栈等
- 控制信息:进程描述符,内核堆栈等
- 硬件上下文(注意中断也要保存硬件上下文只是保存的方法不同)
- schedule 函数选择一个新的进程来运行,并调用 context_switch 宏进行上下文的切换,这个宏又调用 switch_to 宏来进行关键上下文切换
- switch_to 宏中定义了 prev 和 next 两个参数:prev 指向当前进程,next 指向被调度的进程
进程切换函数
schedule函数为调度函数,用以选择切换进程,其主要调用的函数有 pick_next_task,context_switch,在context_switch中调用switch_to。
重点分析下switch_to中的汇编代码
asm volatile("pushfl\n\t" /* 保存当前进程的flags */ "pushl %%ebp\n\t" /* 把当前进程的ebp压入当前进程的栈 */ "movl %%esp,%[prev_sp]\n\t" /*保存当前的esp到prev->thread.sp指向的内存中 */ "movl %[next_sp],%%esp\n\t" /* 重置esp,把下个进程的next->thread.sp赋予esp */ "movl $1f,%[prev_ip]\n\t" /* 把1:的代码在内存中存储的地址保存到prev->thread.ip中 */ "pushl %[next_ip]\n\t" /* 重置eip */ "jmp __switch_to\n" /* regparm call */ "1:\t" "popl %%ebp\n\t" /* 重置ebp */ "popfl\n" /*重置flags*/ /* output parameters */ : [prev_sp] "=m" (prev->thread.sp), /* =m 表示把变量放入内存,即把 [prev_sp] 存储的变量放入内存,最后再写入prev->thread.sp */ [prev_ip] "=m" (prev->thread.ip), "=a" (last), /*=a 表示把变量 last 放入 ax, eax = last */ /* clobbered output registers: */ "=b" (ebx), "=c" (ecx), "=d" (edx), /* b 表示放入ebx, c 表示放入 ecx,d 表示放入 edx, S表示放入 si, D 表示放入 edi */ "=S" (esi), "=D" (edi) /* input parameters: */ : [next_sp] "m" (next->thread.sp), /* next->thread.sp 放入内存中的 [next_sp] */ [next_ip] "m" (next->thread.ip), /* regparm parameters for __switch_to (): */ [prev] "a" (prev), /*eax = prev edx = next*/ [next] "d" (next) : /* reloaded segment registers */ "memory");
其实,在前四行汇编代码执行完,已经切换到了next进程的内核堆栈,但应该还算是在prev进程执行,到了标号1开始,才开始执行next进程。为什么next进程有popl ebp和popf1呢?因为next进程曾经是prev,曾经被push过,即前两句汇编代码,此处可以参考前边对mykernel的理解!
总结
Linux系统的一般执行过程
最一般情况:正在运行的用户态进程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
特殊情况
- 通过中断处理过程中的调度,用户态进程与内核进程之间互相切换,与一般情形类似;
- 内核进程程主动调用 schedule 函数,只有进程上下文的切换,没有中断上下文切换;
- 创建子进程的系统调用在子进程中的执行起点及返回用户态,如:fork;
- 加载一个新的可执行程序后返回到用户态的情况,如:execve;
实验截图
参考实验报告
- 网易云课堂 Linux内核分析(八)
- 网易云课堂 Linux内核分析(一)
- 网易云课堂 Linux内核分析(二)
- 网易云课堂 Linux内核分析(三)
- 网易云课堂 Linux内核分析(四)
- 网易云课堂 Linux内核分析(五)
- 网易云课堂 Linux内核分析(六)
- 网易云课堂 Linux内核分析(七)
- [网易云课堂]Linux内核分析(八)—— 理解进程调度时机跟踪分析进程调度与进程切换的过程
- 网易云课堂 Linux内核分析期末总结
- [网易云课堂]Linux内核分析(一)——简单C程序汇编代码分析
- [网易云课堂]Linux内核分析(五)—— 分析system_call中断处理过程
- [网易云课堂]Linux内核分析(三)—— 跟踪分析Linux内核的启动过程
- [网易云课堂]Linux内核分析(六)—— 分析Linux内核创建一个新进程的过程
- [网易云课堂]Linux内核分析(九)—— 课程总结
- 跟踪分析Linux内核的启动过程|Linux内核分析 第三周作业 - 网易云课堂
- [网易云课堂]Linux内核分析(二)—— mykernel内核部署及简单时间片轮转程序分析
- [网易云课堂]Linux内核分析(七)—— Linux内核如何装载和启动一个可执行程序
- Java反射机制的一些总结
- 排序算法
- matplotlib学习
- 字符串 POJ-1007
- Android中的ContentProvider中的重要点
- 网易云课堂 Linux内核分析(八)
- 操作系统级虚拟化——学习笔记
- 数据库的选择
- 解决Android Studio SVN忽略文件不生效
- 【Redis】--集群理解
- BZOJ1000[A+B Problem]题解--基础题
- WAVE文件格式分析
- [主席树] BZOJ2588: Spoj 10628. Count on a tree
- Java Eclipse中如何快速替换变量