> For the complete documentation index, see [llms.txt](https://s3.shizhz.me/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://s3.shizhz.me/linux-sched/history/o-n-tick.md).

# 2.3.3 O（n）调度器 - 调度时机

聊完了调度的具体逻辑与时间分配之后，我们再来简单聊一下调度时机，即调度这件事情在什么情况下会发生。O(n) 的调度主要发生在如下场景中：

1. 进程主动发起调度，搜索内核代码会发现大量的地方调用了 `schedule()` 方法
2. timer 发现当前进程已经耗尽了自己的时间，触发调度。代码如下：

   ```
   /* file: kernel/timer.c */
   void update_process_times(int user_tick) {
       struct task_struct *p = current;
       int cpu = smp_processor_id(), system = user_tick ^ 1;

       update_one_process(p, user_tick, system, cpu);
       if (p->pid) {
           /* 运行时间耗尽，设置调度标记 */
           if (--p->counter <= 0) {
               p->counter = 0;
               p->need_resched = 1;
           }
           if (p->nice > 0)
               kstat.per_cpu_nice[cpu] += user_tick;
           else
               kstat.per_cpu_user[cpu] += user_tick;
           kstat.per_cpu_system[cpu] += system;
       } else if (local_bh_count(cpu) || local_irq_count(cpu) > 1)
           kstat.per_cpu_system[cpu] += system;
   }
   ```

   在定时器中不会直接触发调度，而是设置任务的调度位： `p->need_resched = 1;`, 系统在下一轮调度中才会做对应的处理。
3. 用户修改进程优先级的时候，这一点很好理解。
4. 系统通过 `fork()` 创建新任务的时候，新任务的产生会导致系统产生调度需求。

还有很多其它的情况会引发调度，这里不再一一列举了。
