linux 中断
local_irq_disable()和 local_irq_enable()都只能禁止和使能本地 CPU 内的中断, 因此,并不能解决 SMP 多 CPU 引发的竞态。因此,单独使用中断屏蔽通常不是一种值得推荐的避免竞态的方法,它适宜与自旋锁联合使用。与 local_irq_disable()不同的是,local_irq_save(flags)除了进行禁止中断的操作以外, 还保存目前 CPU 的中断位信息, local_irq_restore (flags) 进行的是与 local_irq_save(f lags)相反的操作。如果只是想禁止中断的底半部,应使用 local_bh_disable(), 使能被 local_bh_disable()禁止的底半部应该调用 local_bh_enable().
1,申请和释放中断
int request_irq(unsigned int irq, void (*handler)(int irq, void *dev_id, struct pt_regs *regs), unsigned long irqflags, const char * devname, void *dev_id);void free_irq(unsigned int irq,void *dev_id);
2 ,使能和屏蔽中断
void disable_irq(int irq); //等待目前的中断处理完成
void disable_irq_nosync(int irq); //立即返回
void enable_irq(int irq);
void local_irq_save(unsigned long flags); //屏蔽本 CPU 内的所有中断
void local_irq_restore(unsigned long flags);//
void local_irq_disable(void);//屏蔽本 CPU 内的所有中断
void local_irq_enable(void);
底半部实现机制
主要有tasklet , workqueque, softirq
1。 tasklet。
tasklet 的使用较简单, 我们只需要定义 tasklet 及其处理函数并将两者关联。
void my_tasklet_func(unsigned long); /*定义一个处理函数*/
DECLARE_TASKLET(my_tasklet, my_tasklet_func, data); /*定义一个 tasklet 结构 my_tasklet,与 my_tasklet_func(data)函数相关联*/
tasklet_schedule(&my_tasklet);//使系统在适当的时候进行调度运行
/*中断处理顶半部*/
irqreturn_t xxx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{..............................
tasklet_schedule(&xxx_tasklet);
..............................
}
2.workqueque
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也是基于软中断实现的。硬中断是外部设备对 CPU 的中断,软中断通常是硬中断服务程序对内核的中断,而信号则是由内核(或其他进程)对某个进程的中断。用 softirq_action 结构体表征一个软中断,这个结构体中包含软中断处理函数指针和传递给该函数的参数。 使用 open_softirq()函数可以注册软中断对应的处理函数,而 raise_softirq()函数可以触发一个软中断。软中断和 tasklet 仍然运行于中断上下文,而工作队列则运行于进程上下文。 因此,软中断和 tasklet 处理函数中不能睡眠,而工作队列处理函数中允许睡眠。local_bh_disable()和 local_bh_enable()是内核中用于禁止和使能软中断和 tasklet 底半部机制的函数。
内核在软中断子系统初始化时启动了下半部和任务处理队列。 系统在内核进程Ksoftirqd中调用_do_softirq循环检测软中断是否处于pengding状态。
void open_softirq(int nr, void (*action)(struct softirq_action *))
{
softirq_vec[nr].action = action;
}
void __init softirq_init(void)
{
.............................
open_softirq(TASKLET_SOFTIRQ, tasklet_action);
open_softirq(HI_SOFTIRQ, tasklet_hi_action);
}
asmlinkage void do_softirq(void){}
软中断是编译期间静态分配的,软中断可以动态注册注销。
使用过程1,分配索引,一般在BLOCK_SOFTIRQ 与TASKLET_SOFTIRQ间,2,注册处理函数,open_softirq(),3,raise_softirq触发中断。