判断当前上下文类型
每个cpu有一个per-cpu类型的int变量__preempt_count
,它描述了当前抢占信息。
该变量作用划分如下:
* PREEMPT_MASK: 0x000000ff
* SOFTIRQ_MASK: 0x0000ff00
* HARDIRQ_MASK: 0x000f0000
* NMI_MASK: 0x00100000
* PREEMPT_NEED_RESCHED: 0x80000000
相应字段的值用来表示当前的嵌套次数。
在函数中可以通过下面的宏来判断当时与中断、抢占相关的状态:
/*
* Are we doing bottom half or hardware interrupt processing?
* Are we in a softirq context? Interrupt context?
* in_softirq - Are we currently processing softirq or have bh disabled?
* in_serving_softirq - Are we currently processing softirq?
*/
#define in_irq() (hardirq_count())
#define in_softirq() (softirq_count())
#define in_interrupt() (irq_count())
#define in_serving_softirq() (softirq_count() & SOFTIRQ_OFFSET)
它们的判断是通过读取__preempt_count
的值,然后通过掩码方式取出相应部分的值。 这些宏如果为0,表示不处在相应状态;如果不为0则表示位于相应状态,并且其值代表了嵌套次数。
中断Bottom Half推迟
bottom half推迟到下列几种情况:
- 推迟到 top half 执行完毕:softirq机制、tasklet机制
- 推迟到某个指定时间片之后执行:timer类型的softirq
- 推迟到某个内核线程被调度的时候执行:中断线程化处理(threaded irq handler)、workqueue机制
softirq/tasklet执行时机
中断处理将不那么紧急的事情推迟到 bottom half 中执行,具体如何推迟执行又分成两种:
- 有具体时间要求的
- 没有具体时间要求的
没有具体时间要求的又可以分成两种:
- 越快越好型:除了中断 top half 可以抢占其执行外,其他的进程上下文(无论该进程优先级有多高)是无法影响其执行的。softirq、tasklet属于这类。
- 随遇而安型:其执行依赖于系统的调度器。threaded irq handler、workqueue机制属于这类。
softirq在下述情况下可能被得到处理:
- 中断返回用户空间时
- 中断返回内核态的进程上下文时。这种情况发生在当进程调用
local_bh_disable
/local_bh_enable
进入临界区时发生了硬件中断并pending了softirq,但是此硬件中断返回时候不会处理softirq,因为此时依旧是bh disable的,当它返回到临界区中并调用了local_bh_enable
时,在local_bh_enable
中可能会处理。 - 系统非常繁忙,不断地产生中断、raise softirq,因为 Bottom Half 优先级特别高,导致进程无法调度。这种情况下,softirq会推迟到
ksoftirqd
线程中执行。