- 论坛徽章:
- 0
|
本帖最后由 hantor 于 2011-08-05 12:20 编辑
IRQF_NODELAY与tasklet_schedule之间的矛盾
在做Ingo molnar RealTime Linux 驱动,发现了一个很有趣的问题:
(本人使用的是linux2.6.26.8内核,打Ingo molnar RealTime Linux 补丁patch-2.6.26.8-rt16.bz2)
在开发中,尝试了三套方案:
1、在中断中直接调用IO处理函数。
这时候,无论在注册中断函数的时候使用或不使用IRQF_NODELAY标志,程序都能够正常运行。
代码如下:
#define INGO_RT //是否注释此行代码,程序均正常运行。
下面是中断注册程序片段
#ifdef INGO_RT
result = request_irq ( dev->irq,
mycom_interrupt_callback, IRQF_SHARED | IRQF_NODELAY, MYDRIVERNAME, (void *)dev);//使用IRQF_NODELAY标志
#else
result = request_irq ( dev->irq,
mycom_interrupt_callback, IRQF_SHARED , MYDRIVERNAME, (void *)dev);//按普通方式注册中断处理函数
#endif
下面是中断处理函数
void mycom_do_tasklet( unsigned long data )
{
……
}
static irqreturn_t mycom_interrupt_callback(int irqno, void *dev_id)
{
struct mycom_dev *dev = (struct mycom_dev *)dev_id;
if(dev->irq != irqno)//when the interrupt happend,the "irqno" is transfer to the interrupt callback fun
return IRQ_NONE;
tasklet_dev = dev;
// tasklet_schedule( &mycom_tasklet ); //用tasklet实现IO操作,这里注释掉
mycom_do_tasklet( (unsigned long )tasklet_dev );//直接调用IO 操作函数
return IRQ_HANDLED;
}
2、在注册中断的时候使用普通标志注册,中断处理采用tasklet作为底半部
运行结果是:程序正常运行
代码如下:
//#define INGO_RT 将INGO_RT 标志注释掉,注册中断处理函数采用无IRQF_NODELAY方式
void mycom_do_tasklet( unsigned long data );
DECLARE_TASKLET(mycom_tasklet, mycom_do_tasklet, (unsigned long )&tasklet_dev );
下面是中断注册程序片段
#ifdef INGO_RT
result = request_irq ( dev->irq,
mycom_interrupt_callback, IRQF_SHARED | IRQF_NODELAY, MYDRIVERNAME, (void *)dev);//使用IRQF_NODELAY标志
#else
result = request_irq ( dev->irq,
mycom_interrupt_callback, IRQF_SHARED , MYDRIVERNAME, (void *)dev);//按普通方式注册中断处理函数
#endif
下面是中断处理函数
void mycom_do_tasklet( unsigned long data )
{
……
}
static irqreturn_t mycom_interrupt_callback(int irqno, void *dev_id)
{
struct mycom_dev *dev = (struct mycom_dev *)dev_id;
if(dev->irq != irqno)//when the interrupt happend,the "irqno" is transfer to the interrupt callback fun
return IRQ_NONE;
tasklet_dev = dev;
tasklet_schedule( &mycom_tasklet ); //用tasklet实现IO操作
// mycom_do_tasklet( (unsigned long )tasklet_dev );//直接调用IO 操作函数,这里注释掉
return IRQ_HANDLED;
}
3、在注册中断的时候使用IRQF_NODELAY标志注册,中断处理采用tasklet作为底半部
运行结果是:整个系统马上死机,连个OOPS都没有
代码如下:
#define INGO_RT //使用IRQF_NODELAY标志
void mycom_do_tasklet( unsigned long data );
DECLARE_TASKLET(mycom_tasklet, mycom_do_tasklet, (unsigned long )&tasklet_dev );
下面是中断注册程序片段
#ifdef INGO_RT
result = request_irq ( dev->irq,
mycom_interrupt_callback, IRQF_SHARED | IRQF_NODELAY, MYDRIVERNAME, (void *)dev);//使用Ingo RT 中的IRQF_NODELAY标志
#else
result = request_irq ( dev->irq,
mycom_interrupt_callback, IRQF_SHARED , MYDRIVERNAME, (void *)dev);//按普通方式注册中断处理函数
#endif
下面是中断处理函数
void mycom_do_tasklet( unsigned long data );
{
……
}
static irqreturn_t mycom_interrupt_callback(int irqno, void *dev_id)
{
struct mycom_dev *dev = (struct mycom_dev *)dev_id;
if(dev->irq != irqno)//when the interrupt happend,the "irqno" is transfer to the interrupt callback fun
return IRQ_NONE;
tasklet_dev = dev;
tasklet_schedule( &mycom_tasklet ); //用tasklet实现IO操作
// mycom_do_tasklet( (unsigned long )tasklet_dev );//直接调用IO 操作函数,这里注释掉
return IRQ_HANDLED;
}
从上面这三套方案来看,IRQF_NODELAY与tasklet_schedule是一对矛盾。
根据我个人的理解,注册中断处理函数的时候使用IRQF_NODELAY,那么中断处理就不能延时。
而tasklet本身就是一个小延时后才能调度的小任务。所以使用IRQF_NODELAY就不能使用tasklet。
不能使用tasklet的话,那就意味着要在中断处理函数中做较多的工作,需要较多的时间,而这时候是关中断的。
假设这时候又有一个中断到来呢,即使是只有几个us的间隔。
以上分析纯粹个人试验得出的结果,是否正确,请高手指正。
备注:1、Ingo molnar RealTime Patch是红帽公司提供一个RealTime补丁。在实时linux的众多补丁中,它对源代码的修改最少,可以在很少修改源代码的基础上实现RealTime OS。该补丁可以在http://www.kernel.org/pub/linux/kernel/projects/rt/中下载。
2、在2.6内核中,比较高版本的中断标志从原来的SA_变成了IRQF_前缀,并且取消了SA_INTERRUPT标志。
结束语:在linux世界里摸爬打滚,谁都可以提供一套代码,没有一套标准的东西,没有足够的参考文档,只能自己摸索,步履维艰啊!! |
|