linux2.6调度, 请求和执行(触发点和调度时机)

  linux的调度,基本上分成调度请求和调度执行两个部分. 请求的地方不妨称为trigger.执行部分,取名子,应该是check point.

无论2.4/2.6 schedule 是任务调度的实施函数,尽管他们有着本质的不同,这里要谈的是这个函数如何被使用,即,linux采用何种手段和时机
来调度任务.(限于linux内核,而不是从user space中调用放弃cpu的函数)

有几种方式来调度进程:
1. trigger模式
就是2.4中的TASK_NEED_RESCHED,和2.6中的 TIF_NEED_RESCHED和 TIF_NEED_RESCHED_DELAYED. 内核在一些地方将这些标志置位,代表任务需要被调度,称为trigger. 然后在内核的一些必经或者合适的路径,检查这些标志,以决定是否调用schedule,检查这些标志的地方不妨称为"检查点". 检查点中的典型就是返回用户/内核空间的时候, 如果当前进程需要调度,就会调用schedule.另外在内核中一些典型路径也会检查当前任务是否需要调度,这些路径一般是一些广泛存在于各个进程的必经路径.

2." 直接"调用schedule
这里"直接"的意思是相对与trigger模式而言的.这中模式,在调用schedule的时候是根据内核所处的"情景"来主动发起一次调度.而这种模式有可以细分成几种类型: (理解这种情况不妨想想"内核",其实大部分情况下是"处于内核态的线程")
a) 内核在等待某个事件,常见形式是判断某个条件是否满足,不满足则shcedule. 常见模式有:
---通过一个变量传递这种条件,判断条件是否满足来决定是否调用schedule (根据需要有可能采取原子操作)
---等待比较复杂的事件,往往把判断放到一个while循环中来实现
这种模式没有改变当前进程的运行状态,当前任务还是runable的.

b) 内核在等待某个事件,主动进行睡眠(而不是调度,和 a的情景有所不同.)
--中非常常见的模式是wait queue:先设置任务状态为TASK_UNINTERRUPTIBLE/TASK_INTERRUPTIBLE然后调用schedule进
行睡眠,进程一般先加入某个等待队列,合适的地方会唤醒这个等待的进程. 这种情况的典型就是wait_on一些资源的情况.

c)内核中进行长时间的操作,也是常见于一个大的限循环中调用schedule

d)内核主动释放cpu给其他进程以其获得所希望的资源, 比如do_page_fault中标号out_of_memory:调用schedule的情况.

e)就是给其他进程运行机会: 比如idle

3. semaphore的实现
semaphore 使用了schedule来实现加锁失败后的睡眠. 和直接调用schedule有点类似,也是在睡眠中等待一个条件的满足.不同的地方在于唤醒方式: 直接调用schedule中的睡眠一般是在一个等待队列,而semaphore 则是由up来唤醒.

注: 在可被信号唤醒的睡眠的情形下, 重新调度回来要检查是否是接收到信号, 因为信号的处理只有等到返回用户空间的时候才能得到处理,常见于系统调用.

下面我们就从检查点,trigger, 直接调用schedule和semphore几个几个角度来描述2.4和2.6在调度上的不同之处.

2.4.18 和2.6.25.4-rt在任务调度上的不同

检查点:
A) 返回用户空间/返回内核空间:
----2.4 :只在返回user space的时候才会检查任务是否需要被调度.
----2.6:除了保留这个检查点,新增了返回内核空间的检查点, 这个检查点调用 preempt_schedule_irq,这就是抢占式调度. 2.6中调用__schedule前有个关键的操作, add_preempt_count(PREEMPT_ACTIVE),这标志这此schedule是抢占式调度,__schedule 通过PREEMPT_ACTIVE这个标志知道这是一次 抢占. 返回内核空间的时候只有peeempt_count==0才能够抢占当前进程. 2.6在返回用户空间的时候检查两个标志:TIF_NEED_RESCHED和新增的 TIF_NEED_RESCHED_DELAYED, 而返回内核空间只检查TIF_NEED_RESCHED.

B)内核中的其他检查点
这些剩余的检查点分散在diver/mm和fs的一些地方, 这些检查点,能够提高内核的响应速度,这种加查点加速了对当前需要调度的进程的调度速度,而不是只有在返回user space/kernel space的时候才检查. 
----2.4: 比较单纯,就是检查current->need_resched (TASK_NEED_RESCHED),然后调用schedule.
----2.6: 有两种检查点,TIF_NEED_RESCHED和新增的 TIF_NEED_RESCHED_DELAYED.主要区别在A)中已有叙述.另一而主要区别是2.6中扩展了很多抢占式的检查点.
TIF_NEED_RESCHED:返回user space和返回kernel space都要检查.need_resched()也只检查这个标志. 而这个标记实现的检查点又有两种途径:
a)通过preempt_check_resched 实现的检查点,进行的是抢占式调度. 然后直接调用,和通过unlock spin,bh,rwlock这些函数广泛分布到内核各个地方.
b)通过need_resched()实现的检查点: 这个途径实现的检查点一部分是非抢占式调度,另一部分是抢占式调度通,抢占式的检查点都是调用的cond_resched实现的(下面再详细分析这个函 数).直接通过need_resched()来调用schedule和cond_resched的地方不是特别多.
c)直接在一些路径调用cond_resched实现的抢占式检查点.
TIF_NEED_RESCHED_DELAYED: 这个是RT linux patches set进行的扩展, 对应一个need_resched_delayed,然而几乎没有通过这个检查函数实现的检查点. 而preempt_check_resched_delayed()通过被wait queue的__wake_up和complete间接的被广泛应用.


trigger :对应检查点,必须有地方trigger上述的检查点.
---- 2.4.18
2.4中trigger比较有限. 最重要的是时钟中断的 update_process_times, 监视p->counter,等进程消耗完时间片就触发对这个进程的一次调度,其次就是 __schedule_tail->reschedule_idle 在每次调度完成之后试图给prev找到一个合适的CPU去运行, 通过IPI触发另外一个cpu重新调度. 还有就是较少运行的sys_sched_yield,setscheduler.

----2.6.25.4-rt3
TIF_NEED_RESCHED :
设置这个标志的函数主要有两个: resched_task(),set_tsk_need_resched().主要是resched_task,而resched_task的调用者 check_preempt_curr更是通过:try_to_wake_up/wake_up_new_task/pull_task /__migrate_task 这些被广泛使用的函数, 从而分布在内核中大量的检查点有机会抢占进程. 
对应2.4, 最典型的trigger点是hrtick()->curr->sched_class->task_tick->..->set_tsk_need_resched.
TIF_NEED_RESCHED_DELAYED:
对应这个检查点的trigger几乎没有. 看来要fade out了.


直接调用
schedule:
区别不大.

cond_resched:这个函数在内核实现多检查点:
当前进程需要被抢占,且不是处PREEMPT_ACTIVE的环境下,即防止schedule() -> reacquire_kernel_lock() -> down() -> might_sleep()->cond_resched这个循环. 参考patch:
http://lkml.org/lkml/2006/12/26/62
以及这个patch的讨论
http://mail.nl.linux.org/kernelnewbies/2007-02/msg00311.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值