linux 将中断外理函数分解成两个半部:顶半部与低半部。
顶半部完成尽可能少的功能,通常只作“登记中断”,中断具体的工作重心落在低半部。
分成两部分可以改善系统的响应能力,但是,如果中断要处理的工作本身很少,则完全可以直接在顶半部完成。
查看/proc/interrupts文件可以获得体系统中中断的统计信息。第一列:中断号,第二列,中断次数,第三列,中断描述
中断编程
中断申请函数:
int request_irq(unsigned int irq,irq_handler_t handler,
unsigned long irqflags,const char *devname,void *dev_id)
irq:硬件中断号
handler:顶半部程序,dev_id用来传递函数
irqflags:中断处理属性,可以指定中断的触发方式以及处理方式
dev_id:中断共享时才用到
request_irq()返加0表示成功,返回-EINVAL表示中断号无效或处理函数指针为NULL,返回EBUSY表示中断已经被占用且不能共享
顶半部handler的类型irq_handler_t定义为:
typedef irqretrun_t (*irq_handler_t)(int,void *);
typedef int irqreturn_t;
中断释放函数:
void free_irq(unsigned int irq,void *dev_id);
始能和屏蔽中断涵数
屏蔽某一个中断
void disable_irq(int irq);//会等待指定的中断处理完成,在顶半部使用会引起死锁
void disable_irq_nosync(int irq);//立即返回
void enable_irq(int irq);
屏蔽本CPU内所有中断
#define local_irq_save(flags) . . .//这是一个宏,会将原有状态保留在flags中
void loca_irq_disable(void);//不会保留原有状态
与上述对应的函数(宏)是:
#define local_irq_restore(flags);
void local_irq_enable(void);
底半部机制
1、tasklet:
/*我们只需要定义tasklet 及处理函数并将两者关联*/ /*例如:*/ void my_tasklet_func(unsigned long);/*定义一个处理函数*/ DECLARE_TASKLET(my_tasklet, my_tasklet_func,data);/*定义一个tasklet结构体,与函数my_tasklet相关联,data 为传给my_tasklet的函数*/
tasklet_schedule(&my_tasklet);/*引用此函数,使系统在适当的时候进行调度运行*/
tasklet使用模板
/*定义tasklet和底半部函数并关联*/
void xxx_do_tasklet(unsigned long);
DECLARE_TASKLET(xxx_tasklet,xxx_do_tasklet,0);
/*中断处理底半部*/
void xxx_do_tasklet(unsigned long)
{
//...
}
/*中断处理顶半部*/
irqreturn_t xxx_interrupt(int irq, void *dev_id)
{
//...
tasklet_schedule(&xxx_tasklet);
}
/*设备驱动模块加载函数*/
int __init xxx_init(void)
{
//...
/*申请中断*/
result = request_irq(xxx_irq,xxx_interrupt,
IROF_DISABLED,"xxx",NULL);
//...
return IRQ_HANDLED;
}
/*设备驱动模块卸载函数*/
void __exit xxx_exit(void)
{
//...
/*释放申请的中断*/
free_irq(xxx_irq,xxx_interrupt);
//...
}
struct work_struct my_wq; /*定义一个工作队列*/
void my_wq_func(unsigned long);/*定义一个处理函数*/
...
INIT_WORK(&my_wq,(void (*) (void *)) my_wq_func,NULL);/*将工作队列与处理函数绑定*/
...
schedule_work(&my_wq);/*调度工作队列执行*/
3、软中断
顶半部返回时执行,tasklet是基于软中断,运行于软中断上下文
softirq_action 结构体表征一个软中断,包函中断处理函数指针与参数
open_softirq()函数可以注册软中断对应的处理函数
raise_softirq()函数可触发一个软中断
软中断与tasklet运行于软中断上下文,属原子上下文,所以不能睡眠
工作队列运行于进程上下文,因此可允许睡眠
local_bh_disable()和local_bh_enable()用于禁止和使能软中断、tasklet底半部机制函数