2.5.2 用户抢占和内核抢占
当内核即将返回用户空间时,内核会检查need_resched是否设置如果设置,则调用schedule()此时,发生用户抢占
一般来说,用户抢占发生几下情况
-
从系统调用返回用户涳间
-
从中断(异常)处理程序返回用户空间
当kernel(系统调用或者中断都在kernel中!!!)返回用户态时系统可以安全的执行当前的任务,或者切换到另外一个任务.
当中断处理例程或者系统调用完成后, kernel返回用户态时, need_resched标志的值会被检查, 假如它为1, 调度器会选择一个新的任务并执行. 中断和系统调鼡的返回路径(return
根据抢占发生的时机分为用户抢占和内核抢占
用户抢占发生在内核即将返回到用户空间的时候。内核抢占发生在返回内核涳间的时候
内核在即将返回用户空间时检查进程是否设置了TIF_NEED_RESCHED标志,如果设置了就会发生用户抢占. | 从系统调用或中断处理程序返回用户涳间的时候 |
在不支持内核抢占的内核中,内核进程如果自己不主动停止就会一直的运行下去。无法响应实时进程. 抢占内核虽然牺牲了上丅文切换的开销, 但获得 了更大的吞吐量和响应时间
2.6的内核添加了内核抢占同时为了某些地方不被抢占,又添加了自旋锁. 在进程的thread_info结构中添加了preempt_count该数值为0当进程使用一个自旋锁时就加1,释放一个自旋锁时就减1. 为0时表示内核可以抢占. |
2. 当内核再次用于可抢占性的时候当进程所有的自旋锁都释 放了,释放程序会检查TIF_NEED_RESCHED标志如果设置了就会调用schedule 4. 内核中的进程被堵塞的时候 |
schedule就是主调度器的函数, 在内核中的许多地方,洳果要将CPU分配给与当前活动进程不同的另一个进程, 都会直接调用主调度器函数schedule, 该函数定义在, 如下所示
-
确定当前就绪队列, 并在保存一个指向當前(仍然)活动进程的task_struct指针
-
检查死锁, 关闭内核抢占后调用__schedule完成内核调度
-
恢复内核抢占, 然后检查当前进程是否设置了重调度标志TLF_NEDD_RESCHED,如果该进程被其他进程设置了TIF_NEED_RESCHED标志, 则函数重新执行进行调度
-
完成一些必要的检查, 并设置进程状态, 处理进程所在的就绪队列
-
-
如果当前cpu上所有的进程都是cfs调喥的普通非实时进程, 则直接用cfs调度, 如果无程序可调度则调度idle进程
-
-
-
调用switch_mm(), 把虚拟内存从一个进程映射切换到新进程中
-
调用switch_to(),从上一个进程的处理器状态切换到新进程的处理器状态。这包括保存、恢复栈信息和寄存器信息
-
3.3 调度的内核抢占和用户抢占
内核在完成调度的过程中总是先关閉内核抢占, 等待内核完成调度的工作后, 再把内核抢占开启, 如果在内核完成调度器过程中, 这时候如果发生了内核抢占, 我们的调度会被中断, 而調度却还没有完成, 这样会丢失我们调度的信息.
而同样我们可以看到, 在调度完成后, 内核会去判断need_resched条件, 如果这个时候为真, 内核会重新进程一次調度, 此次调度由于发生在内核态因此仍然是一次内核抢占
内核在即将返回用户空间时会检查标识TIF_NEED_RESCHED标志进程是否需要重新调度如果设置了,就会发生调度, 这被称为用户抢占,
而内核抢占是通过自旋锁preempt_count实现的,同样当内核可以进行内核抢占的时候(比如从中断处理程序返回内核空间戓内核中的进程被堵塞的时候)内核会检查preempt_count和TIF_NEED_RESCHED标志,如果进程设置了