调度入口__schedule() 主要做了几件事:
deactivate_task() -> pick_next_task() -> context_switch()
pick_next_task 的实现中主要两个步骤:
- (IN __pick_next_task)
-
- put_prev_task_balance(rq, prev, rf);
-
- for_each_class(class) {
- p = class->pick_next_task(rq);
- if (p)
- return p;
- }
put_prev_task_balance 会从高优先级向低优先级搜索可调度的task,优先级的顺序是:
stop > deadline > real time > fair > idle
在 balance_rt 中如果 pushable_tasks 队列的最高优先级的task比当前优先级要小,且当前任务队列的load 很大了,则尝试为它们决定应该调度到哪个cpu上pull_rt_task()大概过程是:
之后执行 put_prev_task_rt,这里会更新统计信息,如果发现有 task 已经超出了队列的时间片(sched_rt_runtime_exceeded),则尝试从调度域中其它的cpu瓜分时间片过来(do_balance_runtime)。如果成功的话,且这个任务还没结束,则把它放到可调度pushable_tasks队列上(enqueue_pushable_task)。如果无济于事的话,则从各层active 队列里摘除,并尝试插入到上面某个时间片充足的层级的group的active 队列中(dequeue_rt_entity),并重新调度这个实时队列(resched_curr)。
现在假设active队列上还有其它 active 的任务,执行 pick_next_task,找出下一个active 的最高优先级任务:
- static struct task_struct *pick_next_task_rt(struct rq *rq)
- {
- struct task_struct *p = pick_task_rt(rq);
-
- if (p)
- set_next_task_rt(rq, p, true);
-
- return p;
- }
pick_task_rt 会根据bitmap 找到最高优先级的队列,从中拿出第一个task,作为要执行的task。set_next_task_rt 会把这个选中的task从pushable_tasks中摘除下来,并注册一个push_rt_tasks的callback,并在active队列上任务全耗尽时通过__balance_callbacks来调度pushable_tasks中剩下的task。
如果执行过程中有抢占或time_tick到达,则可能会把task 放回 active 队列(requeue_task_rt)。