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);
//...
}

  

2、工作队列

工作队列与tasklet相似

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);/*调度工作队列执行*/

  

void my_wq_func(unsigned long);/*定义一个处理函数*/

...

INIT_WORK(&my_wq,(void (*) (void *)) my_wq_func,NULL);/*将工作队列与处理函数绑定*/

...

schedule_work(&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底半部机制函数

 


 
posted on 2011-07-18 23:51  林德伟  阅读(275)  评论(0编辑  收藏  举报