内核调度时机

本文深入探讨了内核调度的时机,包括主动调度、用户态和内核态抢占的时机,以及延迟调度的概念。详细解释了TIF_NEED_RESCHED标志的作用,以及在不同场景下如何触发调度。

调度的时机

内核中常见的调度场景如下:
(1)进程被阻塞时,比如执行sleep()后,需要立刻执行schedule()进行调度
(2)当唤醒进程时,比如try_to_wake_up()执行时,会重新计算负载,查找需要执行的进程,并设置TIF_NEED_RESCHED标志延时调度
(3)当周期执行的scheduler_tick()发现需要切换进程时,设置TIF_NEED_RESCHED标志延时调度

以上的场景只是个别举例介绍,那么概括起来的话,到底在哪些时间点是内核允许调度的时机呢?
调度发生的时机有如下一些时间点:
主动发生调度:

1)显式调用schedule()

用户态抢占时机:

 1. 从中断返回到用户空间user space:检查TIF_NEED_RESCHED是否为1
 2. 从系统调用返回到用户空间usersapce:检查TIF_NEED_RESCHED是否为1

内核态抢占的时机:

1) 中断返回内核空间:检查preempt_count是否为0和TIF_NEED_RESCHED是否为1。
当一个中断处理例程退出,在返回到内核态时(kernel-space)。这是隐式的调用schedule()函数,当前任务没有主动放弃CPU使用权,而是被剥夺了CPU使用权。
2)  显式或者隐式调preempt_enable()函数:检查preempt_count是否为0和TIF_NEED_RESCHED是否为1
这个隐式的调用,比如spin_unlock_bh和spin_unlock等,都会隐式的调用preempt_enable()函数,进而判断是否需要schedule。
3)使能软中断:检查preempt_count是否为0和TIF_NEED_RESCHED是否为1
使能软中断的函数local_bh_enable中会隐式包含对preempt_count的操作,所以会判断是否可以进行schedule。

需要注意如果内核未使能内核态抢占,那么就调度时机就只能发生于用户态抢占或者主动调度的情况。

延迟调度

直接调度就不用多做介绍了,上面已经提到过,直接显式调用schedule()函数就会触发调度行为,而内核中大部分的内核路径采用的是延迟调度的方式。
所谓延迟调度也就是,我们并不是立刻执行schedule()函数对进程进行调度,而是设置TIF_NEED_RESCHED标志位,当调度时机到来时,检测此标志位,进而调用schedule()进行调度行为。
前面介绍的过什么情况下会检测TIF_NEED_RESCHED标志并进行调度,而设置TIF_NEED_RESCHED标志的地方就是延迟调度发生的地方。

比如:
(1)周期调度函数scheduler_tick()中判断是否满足进程切换的条件,并设置延迟调用的标志位,也就是TIF_NEED_RESCHED标志。
(2)当使用try_to_wake_up唤醒一个进程时,如果唤醒进程的优先级高于当前正在执行的进程时,设置current进程的TIF_NEED_RESCHED标志。
(3)当系统调用sched_setscheduler()时,同样设置current进程的TIF_NEED_RESCHED标志。

为什么要存在延迟调度的方式,通过设置一个TIF_NEED_RESCHED,等到中断/异常返回的时候才执行,而不是直接执行调度行为?
原因如下:
(1)唤醒操作经常在中断上下文中执行,在这个环境中直接调用schedule()进行调度是不行的;
(2)为了维护非抢占内核以来的一些传统,不要轻易中断进程的处理逻辑除非他主动放弃;
(3)在普通上下文中,唤醒后接着调用schedule()也是可以的,比如smp_send_reschedule()、resched_curr()函数就是这么实现。

关键函数

  • schedule()
  • scheduler_tick()
  • try_to_wake_up()
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值