Linux内核抢占的理解

可抢占性,对一个系统的调度延时具有重要意义。2.6 之前,一个进程进入内核态后,别的进程无法抢占,只能等其完成或退出内核态时才能抢占, 这带来严重的延时问题,2.6 开始支持内核态抢占。

禁止内核抢占的情况列出如下:

(1)内核执行中断处理例程时不允许内核抢占,中断返回时再执行内核抢占。
(2)当内核执行软中断或tasklet时,禁止内核抢占,软中断返回时再执行内核抢占。 
(3)在临界区禁止内核抢占,临界区保护函数通过抢占计数宏控制抢占,计数大于0,表示禁止内核抢占。

为保证Linux内核在以上情况下不会被抢占,抢占式内核使用了一个变量preempt_ count,称为内核抢占锁。这一变量被设置在进程的PCB结构task_struct中。每当内核要进入以上几种状态时,变量preempt_ count就加1,指示内核不允许抢占。每当内核从以上几种状态退出时,变量preempt_ count就减1,同时进行可抢占的判断与调度。抢占式Linux内核的修改主要有两点:

一是对中断的入口代码和返回代码进行修改。在中断的入口内核抢占锁preempt_count加1,以禁止内核抢占;在中断的返回处,内核抢占锁preempt_count减1,使内核有可能被抢占。另一基本修改是重新定义了自旋锁、读、写锁,在锁操作时增加了对preempt count变量的操作。在对这些锁进行加锁操作时preemptcount变量加1,以禁止内核抢占;在释放锁时preemptcount变量减1,并在内核的抢占条件满足且需要重新调度时进行抢占调度。

调度的时机

1) 中断返回内核空间:检查preempt_count是否为0和TIF_NEED_RESCHED是否为1 
2) 中断或异常返回到user space:检查TIF_NEED_RESCHED是否为1
3)  显式或者隐式调preempt_enable()函数:检查preempt_count是否为0和TIF_NEED_RESCHED是否为1
4)使能软中断:检查preempt_count是否为0和TIF_NEED_RESCHED是否为1
5)自己主动schedule()

spinlock不允许睡眠,原因就是他设计初衷就是如此,因此在获取spinlock时就调用禁止抢占的函数,所以正常情况下获取锁的CPU是不会被抢占的,但如果工程师代码中进行了睡眠,那么睡眠会导致让出CPU,想象一下,一个低优先级的线程先获取了spinlock,如果来一个高优先级的线程去获取spinlock,就会一直获取不到导致死锁。

你可能感兴趣的:(内核笔记)