# 2.6.2.6 调度逻辑 - 调度时机

从调度器的角度来看，真正的调度（即调度器完成上下文切换，正儿八经地换一个任务来执行）仅发生在函数 `schedule()` 中，剔除额外代码，我们来看一下该函数的主要流程：

```
/* file: kernel/sched/core.c */
asmlinkage __visible void __sched schedule(void) {
struct task_struct *tsk = current;

do {
preempt_disable();
/* 调用函数 __schedule 来做具体的工作 */
__schedule(false);
sched_preempt_enable_no_resched();
/* need_resched用来判断当前任务是否应该被抢占，此时的当前任务就是函数__schedule最新选择的任务，如果是的话那么继续调用函数__schedule以便调用下一个合适的任务。*/
} while (need_resched());
}

static void __sched notrace __schedule(bool preempt) {
struct task_struct *prev, *next;
unsigned long *switch_count;
unsigned long prev_state;
struct rq_flags rf;
struct rq *rq;
int cpu;

/* 获取到当前CPU序号，进而获取到其runqueue */
cpu = smp_processor_id();
rq = cpu_rq(cpu);
/* rq->curr 是当前正在执行的任务 */
prev = rq->curr;

prev_state = prev->state;
if (!preempt && prev_state) {
if (signal_pending_state(prev_state, prev)) {
    prev->state = TASK_RUNNING;
} else {
    /* preempt 如果为false,
        则说明此次调度不是由于任务抢占导致的，那么导致调度发生的原因就是任务主动要求让出CPU,
        对于由于IO事件进入睡眠的任务而言，需要先将其从运行队列中踢出去。该函数最终会调用调度类（sched_class）的
        dequeue_task 方法完成具体工作。*/
    deactivate_task(rq, prev, DEQUEUE_SLEEP | DEQUEUE_NOCLOCK);
}
}

/* 从队列中选择下一个任务，该函数最终会调用调度类（sched_class的函数pick_next_task方法。对于CFS而言，就是选择vruntime最小的任务
*/
next = pick_next_task(rq, prev, &rf);
/* 清除 prev 任务的TIF_NEED_RESCHED标记，因为此时它已经被抢占了 */
clear_tsk_need_resched(prev);

if (likely(prev != next)) {
/* 完成上下文切换，CPU将开始执行刚刚挑出来的任务next了 */
rq = context_switch(rq, prev, next, &rf);
}
}
```

关于选择下一个任务的语句 `next = pick_next_task(rq, prev, &rf);`, 其中函数 `pick_next_task()` 就是我们在调度类中讨论的那个方法，CFS 的实现是函数 `pick_next_task_fair`, 他的主要逻辑就是从红黑树中选择最左侧的任务，我们在这里不再深入细节讨论。

函数 `schedule()` 最后调用 `context_switch()` 完成上下文切换，至此，整个调度工作就完成了！


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://s3.shizhz.me/linux-sched/cfs-sched/logic-time.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
