万子惠 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
进程切换和一般执行过程
Part1 实验部分
Part2 总结部分
进程调度和切换
- 时机:中断处理过程(包括时钟中断、I/O中断、系统调用和异常)中,直接调用schedule(),或者返回用户态时根据need_resched标记调用schedule()
a.对于内核线程 (只有内核态,没有用户态)
i.直接用schedule()进行切换
ii.返回用户态时根据need_reashed标记使用schedule()
b.对于用户进程
只能在中断处理过程中进行调度(无法主动调度,只能被动调度)
中断与进程切换时的不同:
1)中断前后在同一个进程中,只是从用户态转换到内核态【使用保护现场和恢复现场】
2)进程切换时,挂起后是两个进程进行了切换,并且进程上下文中保存的信息更多:【调用context_ switch机制进行上下文切换,这个宏中调用switch_ to进行上下文切换】
用户地址空间:包括程序代码,数据,用户堆栈等
控制信息:进程描述符,内核堆栈等
硬件上下文(注意中断也要保存硬件上下文只是保存的方法不同)
schedule细节查看
在schedule函数中可以看到__schedule():
往下看可以看到:
进入context_task_switch:
到这里就可以看到switch_to了:
对于重要的switch_to(这里有两个进程交换时产生的模糊地带):
switch_to中 next_ip一般是$1f,对于新创建的进程是ret_from_fork
jump_switch_to时return也会return到这一个eip【新】,正常情况下从1:开始
-
原因:不同类型进程有着不同的调度要求
分类方式a:
1)I/O密集【大量时间等待I/O】
2)CPU密集【大量CPU时间运算】
分类方式b:
1)批处理进程【无需交互,后台进行,无需很快响应】
2)实时进程【有实施需求,响应时间要短】
3)交互式进程【多交互,响应要快!】
=>处理策略:Linux调度基于分时和优先级【选择合适的就绪进程】
优先级是动态的:根据进程的行为为周期性调整。
等待时间长,优先级up;在cpu运行时间长优先级down
内核中的调度算法相关代码使用了类似OOD中的策略模式
改变的优先级的系统调用:
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
几种特殊情况
1.通过中断处理过程中的调度时机,用户态进程与内核线程之间互相切换和内核线程之间互相切换,与最一般的情况非常类似,只是内核线程运行过程中发生中断没有进程用户态和内核态的转换;
2.内核线程主动调用schedule(),只有进程上下文的切换,没有发生中断上下文的切换,与最一般的情况略简略;
3.创建子进程的系统调用在子进程中的执行起点及返回用户态,如fork;
新创建的进程起点是ret_from_fork
4.加载一个新的可执行程序后返回到用户态的情况,如execve;
修改了中断上下文的消息
内核是各种中断处理过程和内核线程的集合
Linux架构
输入ls:一个io操作(引入中断)->提交给系统->使用fork生成一个
shell的拷贝
整个系统的运行
从CPU和内存角度来看Linux系统执行:
在Linux中,物理内存总是被映射在3G以上的空间中,若物理内存过大,需要使用其他映射技术。
Q:进程上下文的切换机制,以及与中断上下文切换的关系;