lab5:深入理解进程切换

Linux系统通过schedule()函数选择新进程,接着调用context_switch()和switch_to()进行上下文切换。在切换过程中涉及堆栈、current_thread_info变量、地址空间以及硬件寄存器的更新。switch_to宏实现了包括esp、ebp和ip寄存器的切换,确保进程状态的无缝过渡。
摘要由CSDN通过智能技术生成

lab5:深入理解进程切换

Linux系统中的进程调度过程可以总结为以下几个方面:

1.调度选择从schedule()函数开始,在该函数中进行进程的选择和切换。
2.通过解读switch_to宏中CPU的值的变化,可以分析进程切换的具体执行过程。
3.在进程切换时,堆栈会发生切换位置,切换前后current_thread_info变量也会发生变化。
4.进程切换还涉及到地址空间的切换,但这不会影响后续切换代码的执行。
5.Current宏代表的进程发生变化的源码位置,标志着进程切换的发生。
6.任务状态段中关于内核堆栈的信息发生变化的源码位置,也是进程切换的一部分。

关键函数的调用关系:

schedule() —> context_switch() —> switch_to —> __switch_to()

在Linux内核中,schedule()函数选择一个新的进程来运行,并调用context_switch进行上下文的切换,这个宏调用switch_to来进行关键上下文切换。部分函数具体代码如下,一个调度新进程,一个是进行上下文切换,还有相关堆栈信息的保存。

static void __sched notrace __schedule(bool preempt)
{
	struct task_struct *prev, *next; 
	......    
	next = pick_next_task(rq, prev, &rf);
    ......
	if (likely(prev != next)) {
		......
		rq = context_switch(rq, prev, next, &rf);
	} else {
		......
	}
	balance_callback(rq);
}

next= pick_next_task(rq, prev);//进程调度算法都封装这个函数内部

context_switch(rq,prev, next);//进程上下文切换

static __always_inline struct rq *
context_switch(struct rq *rq, struct task_struct *prev,
          struct task_struct *next, struct rq_flags *rf)
{
   ......
   if (!next->mm) {
   	enter_lazy_tlb(prev->active_mm, next);

   	next->active_mm = prev->active_mm;
   	if (prev->mm)
   		mmgrab(prev->active_mm);
   	else
   		prev->active_mm = NULL;
   } else {
   	membarrier_switch_mm(rq, prev->active_mm, next->mm);
   	switch_mm_irqs_off(prev->active_mm, next->mm, next);

   	if (!prev->mm) {
   		rq->prev_mm = prev->active_mm;
   		prev->active_mm = NULL;
   	}
   }
   ......
   switch_to(prev, next, prev);
   ......
}

switch_to利用了prev和next两个参数:prev指向当前进程,next指向被调度的进程.内核在switch_to中执行如下操作:

1.进程切换, 即esp的切换, 由于从esp可以找到进程的描述符

2.硬件上下文切换, 设置ip寄存器的值, 并jmp到__switch_to函数

3.堆栈的切换, 即ebp的切换, ebp是栈底指针, 它确定了当前用户空间属于哪个进程

swtich_to 紧接着调用 __switch_to_asm,x86下汇编代码如下:

ENTRY(__switch_to_asm)
  UNWIND_HINT_FUNC
  /*
   * Save callee-saved registers
   * This must match the order in inactive_task_frame
   */
  pushq  %rbp
  pushq  %rbx
  pushq  %r12
  pushq  %r13
  pushq  %r14
  pushq  %r15

  /* switch stack */
  movq  %rsp, TASK_threadsp(%rdi) // 保存旧进程的栈顶
  movq  TASK_threadsp(%rsi), %rsp // 恢复新进程的栈顶

  /* restore callee-saved registers */
  popq  %r15
  popq  %r14
  popq  %r13
  popq  %r12
  popq  %rbx
  popq  %rbp

  jmp  __switch_to
END(__switch_to_asm)

总结

Linux系统的进程切换的一般执行过程是这样的,从进程X转向进程Y的过程是这样的。

1.正在运行的用户态进程X 。

2.发生中断——save cs:eip/esp/eflags(current)to kernel stack,then load cs:eip(entry of a specific ISR) and ss:esp(point tokernel stack)。

3.SAVE_ALL//保存现场。

4.中断处理过程中或中断返回前调用了schedule(),其中的switch_to做了关键的进程上下文切换。

5.标号1之后开始运行用户态进程Y(这里Y曾经通过以上步骤被切换出去过因此可以从标号1继续执行)。

6.restore_all //恢复现场。

7.iret- pop cs:eip/ss:esp/eflags from kernel stack //恢复。

8.继续运行用户态进程Y

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值