Lab5 深入理解进程切换

文章详细分析了Linux内核中的context_switch函数,该函数是进程切换的核心,涉及地址空间切换、处理器状态切换,包括switch_mm和switch_to等关键步骤,这些步骤确保了进程间内存管理和处理器状态的有效转换。
摘要由CSDN通过智能技术生成

Lab5 深入理解进程切换

进程上下文切换主要涉及到两部分主要过程:进程地址空间切换和处理器状态切换。地址空间切换主要是针对用户进程而言,而处理器状态切换对应于所有的调度单位。进程切换的框架主要位于context_switch函数中,本文以Linux 内核中的上下文切换函数 context_switch 为中心,分析并深入理解进程切换。

static __always_inline struct rq *
context_switch(struct rq *rq, struct task_struct *prev,
         struct task_struct *next, struct rq_flags *rf)
{
  prepare_task_switch(rq, prev, next);

  /*
   * For paravirt, this is coupled with an exit in switch_to to
   * combine the page table reload and the switch backend into
   * one hypercall.
   */
  arch_start_context_switch(prev);

  /*
   * kernel -> kernel   lazy + transfer active
   *   user -> kernel   lazy + mmgrab() active
   *
   * kernel ->   user   switch + mmdrop() active
   *   user ->   user   switch
   */
  if (!next->mm) {                                // to kernel
    enter_lazy_tlb(prev->active_mm, next);

    next->active_mm = prev->active_mm;
    if (prev->mm)                           // from user
      mmgrab(prev->active_mm);
    else
      prev->active_mm = NULL;
  } else {                                        // to user
    membarrier_switch_mm(rq, prev->active_mm, next->mm);
    /*
     * sys_membarrier() requires an smp_mb() between setting
     * rq->curr / membarrier_switch_mm() and returning to userspace.
     *
     * The below provides this either through switch_mm(), or in
     * case 'prev->active_mm == next->mm' through
     * finish_task_switch()'s mmdrop().
     */
    switch_mm_irqs_off(prev->active_mm, next->mm, next);

    if (!prev->mm) {                        // from kernel
      /* will mmdrop() in finish_task_switch(). */
      rq->prev_mm = prev->active_mm;
      prev->active_mm = NULL;
    }
  }

  rq->clock_update_flags &= ~(RQCF_ACT_SKIP|RQCF_REQ_SKIP);

  prepare_lock_switch(rq, next, rf);

  /* Here we just switch the register state and the stack. */
  switch_to(prev, next, prev);
  barrier();

  return finish_task_switch(prev);
}

context_switch其实是一个分配器, 他会调用所需的特定体系结构的方法

调用switch_mm(), 把虚拟内存从一个进程映射切换到新进程中

switch_mm更换通过task_struct->mm描述的内存管理上下文, 该工作的细节取决于处理器, 主要包括加载页表, 刷出地址转换后备缓冲器(部分或者全部), 向内存管理单元(MMU)提供新的信息

调用switch_to(),从上一个进程的处理器状态切换到新进程的处理器状态,这包括保存、恢复栈信息和寄存器信息

switch_to切换处理器寄存器的呢内容和内核栈(虚拟地址空间的用户部分已经通过switch_mm变更, 其中也包括了用户状态下的栈, 因此switch_to不需要变更用户栈, 只需变更内核栈), 此段代码严重依赖于体系结构, 且代码通常都是用汇编语言编写

进程切换过程中执行的函数

1、prepare_arch_switch()切换前的准备工作
在进程切换之前, 首先执行调用每个体系结构都必须定义的prepare_task_switch挂钩, 这使得内核执行特定于体系结构的代码, 为切换做事先准备. 大多数支持的体系结构都不需要该选项

/**
 * prepare_task_switch - prepare to switch tasks
 * @rq: the runqueue preparing to switch
 * @prev: the current task that is being switched out
 * @next: the task we are going to switch to.
 *
 * This is called with the rq lock held and interrupts off. It must
 * be paired with a subsequent finish_task_switch after the context
 * switch.
 *
 * prepare_task_switch sets up locking and calls architecture specific
 * hooks.
 */
static inline void
prepare_task_switch(struct rq *rq, struct task_struct *prev,
            struct task_struct *next)
{
    sched_info_switch(rq, prev, next);
    perf_event_task_sched_out(prev, next);
    fire_sched_out_preempt_notifiers(prev, next);
    prepare_lock_switch(rq, next);
    prepare_arch_switch(next);
}

2、arch_start_context_switch()
该函数给各个体系结构专有的开始上下文切换的工作提供了入口,不同体系结构的实现不同。

3、最后用switch_to完成了进程的切换
该函数切换了寄存器状态和栈, 新进程在该调用后开始执行, 而switch_to之后的代码只有在当前进程下一次被选择运行时才会执行执行环境的切换是在switch_to()中完成的, switch_to完成最终的进程切换,它保存原进程的所有寄存器信息,恢复新进程的所有寄存器信息,并执行新的进程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值