Linux中断管理中有个非常重要的设计理念就是上下半部机制
上半部就是硬件中断管理
中断设计为上下半部的原因如下
1.硬件中断处理程序以异步方式进行 它会打断其他重要的代码执行 因此为了避免被打断的程序停止时间太长 硬件中断处理程序必须尽快完成
2.硬件中断处理程序通常在关闭中断的情况下执行 关闭中断就是关闭本CPU的所有中断响应 关闭中断后 本地CPU就不能响应所有的中断响应 因此硬件中断处理程序必须尽快的完成
比如 在ARM处理器下 中断发生时 ARM处理器会自动的关闭IRQ/FIQ中断 知道从中断处理程序退出时才打开本地中断
上半部通常是完成整个中断处理任务中的一小部分 例如响应中断表明中断已经被软件接收 简单的数据处理 如DMA 以及硬件中断处理完成时发送EOI信号 给中断控制器等 下半部就是操作一些比较耗时的操作 比如数据复制 数据包的封装之类的 下半部执行的关键点是允许响应所有的中断 是一个开中断的环境
对于中断下半部分
目前只有块设备和网络子系统使用了软中断类型 tasklet机制也是软中断类型中的一种
Linux中定义的软中断类型如下
include/linux/interrupt.h
enum
{
HI_SOFTIRQ=0, //最高优先级的软中断类型
TIMER_SOFTIRQ,//Timer定时器的软中断
NET_TX_SOFTIRQ,//发送网络数据包的软中断
NET_RX_SOFTIRQ,//接收网络数据包的软中断
BLOCK_SOFTIRQ,//块设备软中断
BLOCK_IOPOLL_SOFTIRQ,
TASKLET_SOFTIRQ,//专门为tasklet机制准备的软中断
SCHED_SOFTIRQ,//进程调度以及负载均衡
HRTIMER_SOFTIRQ, /* Unused, but kept as tools rely on the // 高精度定时器
numbering. Sigh! */
RCU_SOFTIRQ, //专门为RCU服务的软中断
NR_SOFTIRQS //最多支持的软中断类型的数目 这里是10
};
softirq_action结构体 当触发软中断时 触发这个action函数的执行
struct softirq_action
{
void (action)(struct softirq_action );
};
中断描述符数组 软中断的索引号就是该数组的索引
static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp;
中断状态信息
typedef struct {
unsigned int __softirq_pending;
} ____cacheline_aligned irq_cpustat_t;
注册软中断API
void open_softirq(int nr, void (action)(struct softirq_action ))
{
softirq_vec[nr].action = action;
}
这个nr就是TASKLET_SOFTIRQ或者其他 linux定义了十种
触发软中断API
void raise_softirq(unsigned int nr)
{
unsigned long flags;
local_irq_save(flags); //保存中断 标志位 我也不知道有什么用
raise_softirq_irqoff(nr);
local_irq_restore(flags);
}
inline void raise_softirq_irqoff(unsigned int nr)
{
__raise_softirq_irqoff(nr);
/*
* If we're in an interrupt or softirq, we're done
* (this also catches softirq-disabled code). We will
* actually run the softirq once we return from
* the irq or softirq.
*
* Otherwise we wake up ksoftirqd to make sure we
* schedule the softirq soon.
*/
if (!in_interrupt()) //判断是否在进程上下文中
wakeup_softirqd();
}
if (!in_interrupt())只是判断是否在进程上下文中 如果在进程上下文中就调用wakeup_softirqd();来唤醒ksoftirqd内核线程来处理 如果在中断上下文中 只需要设置本地CPU __
void __raise_softirq_irqoff(unsigned int nr)
{
trace_softirq_raise(nr);
or_softirq_pending(1UL << nr);
}
void __raise_softirq_irqoff(unsigned int nr)
{
trace_softirq_raise(nr);
or_softirq_pending(1UL << nr);
}
#define or_softirq_pending(x) (local_softirq_pending() |= (x))
#define local_softirq_pending() \
__IRQ_STAT(smp_processor_id(), __softirq_pending)
#define __IRQ_STAT(cpu, member) (irq_stat[cpu].member)
替换也即是irq_stat[cpu].__softirq_pending|= (1<