Lab5:深入理解进程切换
首先找到对应进程调度的代码文件
Kernal/sched/core.c

找到 context_switch() 函数

其中包括rq,为进程的running queue;以及进程切换前后的进程描述符prev和next

首先调用一些函数做上下文切换的准备,与最后出现的finish_task_switch()成对使用

接着进行进程地址空间的切换
(1) 对于next->mm为空的情况,这是一个内核级线程(to kernal),此时linux使用active_mm指向其实际地址空间。此时首先调用entry_lazy_tlb进入lazy_tlb模式

接着将prev进程的active_mm赋给next进程,并在prev进程是用户进程的情况下调用mmgrab,增加prev的active_mm空间的引用计数,因为它现在同时被next进程所持有。

在prev是内核进程的情况下,将其active_mm指针置空即可
(2) 对于其他情况 ,即next为一个用户线程,调用membarrier_switch_mm创建内存屏障,保证进程访问mm的先后顺序

接着调用switch_mm_irqs_off进行地址空间切换,这是一个很长的函数?

之后对从内核进程切换过来的情况设置rq的prev_mm为切换前线程的active_mm,并将该指针置空
最后会调用switch_to()


该函数主要进行寄存器和堆栈的切换,其中调用了prepare_switch_to进行准备工作,并调用_switch_to_asm()函数进行了从prev到next内核堆栈的真正切换,

在最后不使用ret指令,通过jmp指令跳转到_switch_to()函数,在_switch_to()函数中return。_switch_to_asm()中进行了堆栈的切换,
_switch_to()返回后,回到的是next进程而不是prev进程的内核堆栈。