万子惠 + 原创作品转载请注明出处 + 《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:进程上下文的切换机制,以及与中断上下文切换的关系;