调度时机分析之被动调度(之内核态抢占调度)

之前写的两个博客中讲了调度时机的用户态抢占调度部分,分别讲了系统调用返回和中断处理返回这两个点的用户态抢占的一些情况。

这篇博客会写内核抢占调度的部分。

------------------------------------------------------------------------------------------------------------------------------

内核态抢占调度

内核态抢占调度发生在下面两者情况:

◆内核进程运行过程中没有关抢占,有中断产生,在中断返回时,判断出没有关抢占就会调用preempt_schedule_irq函数

◆内核进程运行过程中又产生了更高优先级的进程。

 

早期的Linux内核版本不支持内核态抢占,内核进程的切换需要主动调度,这样调度延迟大,无法做到实时调度。实现可抢占内核的主要修改就是在中断处理返回时,如果是返回内核态,在通过一些检查后,就会调用preempt_schedule_irq函数。

 

下面从中断处理返回开始分析。在前面讲到如果中断返回时返回到内核态,就会跳转到retint_kernel执行

 

/* Returning to kernel space. Check if we need preemption */

/* rcx: threadinfo. interrupts off. */

.p2align

retint_kernel:

cmpl $0,threadinfo_preempt_count(%rcx)  //判断是否关抢占了

jnz  retint_restore_args                //关抢占了不能抢占恢复被中断时的处理器的状态

bt  $TIF_NEED_RESCHED,threadinfo_flags(%rcx)   /*检测是否有设置TIF_NEED_RESCHED标志,是否需要重新调度*/

jnc  retint_restore_args       //不需要重新调度恢复被中断时的处理器的状态

bt   $9,EFLAGS-ARGOFFSET(%rsp)/* interrupts off? */  /*1:响应可屏蔽中断 0:抑制可屏蔽中断*/

jnc  retint_restore_args      //IF标志清零了,恢复被中断时的处理器的状态

call preempt_schedule_irq     

jmp exit_intr

 

首先判断是否关抢占了,如果关抢占了,那么不能抢占,就跳转到retint_restore_args恢复被中断时的处理器状态。

判断是否有设置TIF_NEED_RESCHED标志,需要重新调度,如果不需要的话,也是跳转到retint_restore_args执行。

判断EFLAGS寄存器的IF标志,如果IF标志清零了,说明现在中断上下文所在的中断不是外部可屏蔽中断,也就是内部中断(或外部不可屏蔽中断),这种情况下不考虑内核态抢占的情况,直接跳转到retint_restore_args恢复被中断时的处理器状态。

 

上面的检查都通过之后,就会调用preempt_schedule_irq函数执行。此函数是在退出中断上下文时开抢占的情况下进程抢占调度的入口点。

 

asmlinkage void __sched preempt_schedule_irq(void 

  

           BUG_ON(ti->preempt_count || !irqs_disabled());  

  

 need_resched:  

  add_preempt_count(PREEMPT_ACTIVE);  

  

  local_irq_enable();  

  schedule();  

  local_irq_disable();  

 

  sub_preempt_count(PREEMPT_ACTIVE);  

  

  barrier();  

  if (unlikely(test_thread_flag(TIF_NEED_RESCHED)))  

   goto  need_resched 

 }

 

函数首先检查是关抢占或者开中断了,如果这两种情况任何一个满足,则报错。此函数是在关中断的情况下调用的,这样是为了避免出现中断中递归的调用此函数。

接着调用add_preempt_count(PREEMPT_ACTIVE)函数设置PREEMPT_ACTIVE,这样在后面的schedule函数中见到设置了PREEMPT_ACTIVE,就不会将先前的prev进程从运行队列中移除了。这样能够防止在内核抢占时错误的将当前进程切入阻塞状态。

错误的切入阻塞状态,会有什么后果?如果一个内核进程刚刚调用set_current_state(TASK_INTERRUPTIBLE)后被中断打断,那么在中断返回时,在schedule函数里判断此进程不是TASK_RUNNING状态,如果不加上设置PREEMPT_ACTIVE,就会将此进程从运行队列中移除,不再运行,此进程后面的代码没有得到执行,今后也没有机会被唤醒执行到了。

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值