张嘉琪 原创做品转载请注明出处 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000算法
中断处理过程(包括时钟中断、I/O中断、系统调用和异常)中,直接调用schedule(),或者返回用户态时根据need_resched标记调用schedule();架构
内核线程能够直接调用schedule()进行进程切换,也能够在中断处理过程当中进行调度,也就是说内核线程做为一类的特殊的进程能够主动调度,也能够被动调度;函数
用户态进程没法实现主动调度,仅能经过陷入内核态后的某个时机点进行调度,即在中断处理过程当中进行调度。post
为了控制进程的执行,内核必须有能力挂起正在CPU上执行的进程,并恢复之前挂起的某个进程的执行,这叫作进程切换、任务切换、上下文切换; 挂起正在CPU上执行的进程,与中断时保存现场是不一样的,中断先后是在同一个进程上下文中,只是由用户态转向内核态执行;操作系统
进程上下文包含了进程执行须要的全部信息线程
用户地址空间:包括程序代码,数据,用户堆栈等rest
控制信息:进程描述符,内核堆栈等blog
硬件上下文(注意中断也要保存硬件上下文只是保存的方法不一样)进程
schedule()函数选择一个新的进程来运行,并调用contextswitch进行上下文的切换,这个宏调用switchto来进行关键上下文切换ip
next = picknexttask(rq, prev);//进程调度算法都封装这个函数内部
context_switch(rq, prev, next);//进程上下文切换
switch_to利用了prev和next两个参数:prev指向当前进程,next指向被调度的进程
最通常的状况:正在运行的用户态进程X切换到运行用户态进程Y的过程
经过中断处理过程当中的调度时机,用户态进程与内核线程之间互相切换和内核线程之间互相切换,与最通常的状况很是相似,只是内核线程运行过程当中发生中断没有进程用户态和内核态的转换;
内核线程主动调用schedule(),只有进程上下文的切换,没有发生中断上下文的切换,与最通常的状况略简略;
建立子进程的系统调用在子进程中的执行起点及返回用户态,如fork; 加载一个新的可执行程序后返回到用户态的状况,如execve;
理解Linux系统中进程调度的时机,能够在内核代码中搜索schedule()函数,看都是哪里调用了schedule()
使用gdb跟踪分析一个schedule()函数 ,验证您对Linux系统进程调度与进程切换过程的理解;推荐在实验楼Linux虚拟机环境下完成实验。 特别关注并仔细分析switch_to中的汇编代码,理解进程上下文的切换机制,以及与中断上下文切换的关系;
博客内容中须要仔细分析进程的调度时机、switch_to及对应的堆栈状态等。
1.打开qemu和gdb
2.设置断点
3.用list查看代码
4.单步执行发现__schedule()
5.进入函数
6.继续单步执行直到发现pick_nexi_task()
7.在pick_next_task处设立断点,执行
8.在context_switch处设立断点,执行
对“Linux系统通常执行过程”的理解
Linux内核中实现进程的切换主要经过保存进程相关的信息实现,这里须要注意进程切换中内核级进程的切换和用户态进程切换的不一样。内核态能够直接调用schedule函数并不须要陷入中断这个过程。而用户态则须要陷入内核态才能实现进程的切换。从switch_to这个函数当中也能够验证咱们进程切换时会保存相关信息的推断。