http://blog.chinaunix.net/uid-27767798-id-3577069.html
每个cpu都有自己的运行队列,如果当前cpu上运行的任务都已经dequeue出运行队列,而且idle_balance也没有移动到当前运行队列的任务,那么schedule函数中,按照rt ,cfs,idle这三种调度方式顺序,寻找各自的运行任务,那么如果rt和cfs都未找到运行任务,那么最后会调用idle schedule的idle进程,作为schedule函数调度的下一个任务。
kernel/sched.c 中的schedule()函数中的片段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
这里 PREEMPT_ACTIVE是个标志位,由于进程由于系统调用或者中断异常返回到用户态之前,都要判断是否可以被抢占,会首先判断preempt_count,等于0的时候表示没有禁止抢占,然后再去判断是否标记了need_resched,如果标记了,在去调用schedule函数,如果在某些时候禁止了抢占,禁止了一次就要preempt_count加1。可以肯定的一点是进程的state和是否在运行队列的因果关系并不是十分同步的,修改了进程的状态后,可能还需要做一些其他的工作才去调用schedule函数。引用一下其他人的例子。
1 2 3 4 5 6 |
|
可以看出在修改了进程的state之后,并不会立刻调用schedule函数,即使立刻调用了schedule函数,也不能保证在schedule函数之前的禁止抢占开启之前有其他的抢占动作。毕竟修改进程的state和从运行队列中移除任务不是一行代码(机器码)就能搞定的事情。所以如果在修改了进程的状态之后和schedule函数禁止抢占之前有抢占动作(可能是中断异常返回),如果这个时候进程被其他进程抢占,这个时候把当前进程移除运行队列,那么这个进程将永远没有机会运行后面的代码。所以这个时候在抢占的过程之前将preempt_count标记PREEMPT_ACTIVE,这样抢占中调用schedule函数将不会从当前运行队列中移除当前进程,这样才有前面分析schedule函数代码,有判断进程state同时判断preempt_count未标记PREEMPT_ACTIVE的情况。
在当前进程被移除出运行队列之前还需要判断是否有挂起的信号需要处理,如果当前进程的状态是TASK_INTERRUPTIBLE或者TASK_WAKEKILL的时候,如果还有信号未处理,那么当前进程就不需要被移除运行队列,并且将state置为running。
1 2 3 4 5 6 7 8 9 |
|
说下 put_prev_task的逻辑,按照道理说应该是rt,cfs,idle的顺序寻找待运行态的任务。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
从每个调度类的代码的最后可以看出这个next关系
sched_rt.c中:
1 2 |
|
sched_fair.c中:
1 2 |
|
那么可以试想如果rt和cfs都没有可以运行的任务,那么最后就是调用idle的pick_next_task函数
sched_idletask.c:
1 2 3 4 5 6 |
|
这idle进程在启动start_kernel函数的时候调用init_idle函数的时候,把当前进程(0号进程)置为每个rq的idle上。
kernel/sched.c:5415
1
|
|
这里idle就是调用start_kernel函数的进程,就是0号进程。
0号进程在fork完init进程等之后,进入cpu_idle函数,大概的逻辑是for循环调用hlt指令,每次hlt返回后,调用schedule函数,具体的流程现在还没太看懂,可以看到的是在具体的逻辑在default_idle函数中,调用了safe_halt函数
1 2 3 4 |
|
关于hlt指令的作用是:引用wiki百科
In the x86 computer architecture, HLT (halt) is an assembly language instruction which halts the CPU until the next external interrupt is fired.[1] Interrupts are signals sent by hardware devices to the CPU alerting it that an event occurred to which it should react. For example, hardware timers send interrupts to the CPU at regular intervals.
The HLT instruction is executed by the operating system when there is no immediate work to be done, and the system enters its idle state. In Windows NT, for example, this instruction is run in the “System Idle Process”.
可以看到注释的意思是,hlt指令使得cpu挂起,直到有中断产生这个时候cpu重新开始运行。所以时钟中断会唤醒正在hlt中的cpu,让它调用schedule函数,检测是否有新的任务在rq中,如果有的话切换到新的任务,否则继续执行hlt,cpu继续挂起。