基于内核3.8
对于Linux中断,硬件中断(中断的上半部分)没有什么基础概念,主要源自中断的下半部(BH)。
在讲解中断之前,首先讲解线程结构体,这里主要关注struct thread_info 结构体,其结构如下:
1. 变量:preempt_count
我们在提到,一个线程的禁止被抢占的时候,可能比较好理解,因为线程结构体里面有这个preempt_count成员,如果禁止被抢占,即增加这个技术就可以了。可是当我们提到在中断中禁止中断被抢占(一般指中断下半部-软中断,上半部主要是针对中断嵌套),里面用到的依然是这个变量,那么在软中断(或中断)中使用的是不是这个变量呢?答案是是肯定的。因为不管我们是硬中断抢占软中断,还是硬中断抢占线程,还是软中断抢占线程,其实归根结底都是抢占的线程。
struct thread_info {
struct task_struct *task; /* main task structure */
struct exec_domain *exec_domain; /* execution domain */
int cpu; /* cpu we're on */
int preempt_count; /* 0 => preemptable,
<0 => BUG */
int preempt_lazy_count; /* 0 => preemptable,
<0 => BUG */
struct restart_block restart_block;
unsigned long local_flags; /* private flags for thread */
/* low level flags - has atomic operations done on it */
unsigned long flags ____cacheline_aligned_in_smp;
};
线程变量preempt_count,主要分4个部分,如下所示:
bit31-24(区域A) | bit23-16(区域B) | bit15-8(区域C) | bit7-0(区域D) |
其他 | 硬中断计数 | 软中断计数 | 普通抢占 |
如果线程禁止其他线程抢占,通过调用宏:preempt_disable(),其做的工作主要是增加线程的preempt_count的值,其实也就是增加了这个值的区域D的值,如果其要禁止中断下半部抢占的话就在下半部对于的区域C增加一个值。依次类推。
2. 关于软中断:
在《Linux内核设计与实现》一书中提到同一个CPU上面只允许软中断的一个实例运行,当时我一直没有弄明白这句话是什么意思。正如我们所知的,关于软中断每个CPU都维持着一个32位的位图,这个位图中的每一位都对应着一个类型的软中断,为什么要一个类型而不是一个软中断呢?主要由于里面的软中断有的是tasklet,如下内核的定义:
enum
{
HI_SOFTIRQ=0,
TIMER_SOFTIRQ,
NET_TX_SOFTIRQ,
NET_RX_SOFTIRQ,
BLOCK_SOFTIRQ,
BLOCK_IOPOLL_SOFTIRQ,
TASKLET_SOFTIRQ,
SCHED_SOFTIRQ,
HRTIMER_SOFTIRQ,
RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */
NR_SOFTIRQS
};
这个是我们在linux-3.8中定义的软中断,上面的HI_SOFTIRQ和TASKLET_SOFTIRQ我们看到的是tasklet的下半部,这个可能对应很多下半部。所以说每个CPU维持的这个位图每一位对应着是一类软中断。对于同一个CPU只能运行一个软中断实例以及同一个软中断实例可以在不同的CPU上运行这部分的讲解将在后续描述!