中断处理函数中不用disable_irq而用disable_irq_nosync的原因

今天在写触摸屏驱动时在中断处理函数中使用disable_irq关中断发现在进入中断处理后内核就挂掉了.

于是研究了一下才发现disable_irq关闭中断并等待中断处理完后返回, 而disable_irq_nosync立即返回.

在中断处理程序中应该使用disable_irq_nosync来关闭中断.


先看一下disable_irq_nosync,内核代码中是这样解释的:
/**
 *    disable_irq_nosync - disable an irq without waiting
 *    @irq: Interrupt to disable
 *
 *    Disable the selected interrupt line. Disablesand Enables are
 *    nested.
 *    Unlike disable_irq(),this function doesnot ensure existing
 *    instances of the IRQ handler have completed before returning.
 *
 *    This function may be called from IRQ context.
 */
void disable_irq_nosync(unsigned int irq)
{
    struct irq_desc *desc = irq_to_desc(irq);
    unsigned long flags;

    if (!desc)
        return;

    chip_bus_lock(irq, desc);
    spin_lock_irqsave(&desc->lock, flags);
    __disable_irq(desc, irq, false);
    spin_unlock_irqrestore(&desc->lock, flags);
    chip_bus_sync_unlock(irq, desc);
}
关闭中断后程序返回, 如果在中断处理程序中, 那么会继续将中断处理程序执行完.
/**
 * disable_irq - disable an irq and wait for completion
 * @irq: Interrupt to disable
 *
 * Disable the selected interrupt line. Enables and Disables are
 * nested.
 * This function waits for any pending IRQ handlers for this interrupt
 * to complete before returning. If you use this function while
 * holding a resource the IRQ handler may need you will deadlock.
 *
 * This function may be called - with care - from IRQ context.
 */
void disable_irq(unsignedint irq)
{
        struct irq_desc *desc = irq_desc + irq;
        if (irq>= NR_IRQS)
                return;
        disable_irq_nosync(irq);
        if (desc->action)
                synchronize_irq(irq);
}
关闭中断并等待中断处理完后返回.
从代码中可以看到, disable_irq先是调用了disable_irq_nosync, 然后检测desc->action是否为1.
在中断处理程序中, action是置1的, 所以进入synchronize_irq函数中,即等待上一个中断处理结束再处理这次的中断,这时如果上一个中断就是自己本身这个中断,那就完蛋了.内核会崩溃.
/**
 * synchronize_irq - wait for pending IRQ handlers (on other CPUs)
 * @irq: interrupt number to wait for
 *
 * This function waits for any pending IRQ handlers for this interrupt
 * to complete before returning. If you use this function while
 * holding a resource the IRQ handler may need you will deadlock.
 *
 * This function may be called - with care - from IRQ context.
 */
void synchronize_irq(unsignedint irq)
{
 struct irq_desc *desc= irq_to_desc(irq);
 unsigned int status;
 if (!desc)
  return;
 do {
  unsigned long flags;
  /*
   * Wait until we're out of the critical section. This might
   * give the wrong answer due to the lack of memory barriers.
   */
  while (desc->status& IRQ_INPROGRESS)
   cpu_relax();
  /* Ok, that indicated we're done: double-check carefully. */
  spin_lock_irqsave(&desc->lock, flags);
  status = desc->status;
  spin_unlock_irqrestore(&desc->lock, flags);
  /* Oops, that failed? */
 } while (status & IRQ_INPROGRESS);
 /*
  * We made sure that no hardirq handler is running. Now verify
  * that no threaded handlers are active.
  */
 wait_event(desc->wait_for_threads,!atomic_read(&desc->threads_active));
}
注释中说明该函数是在等待中断处理程序的结束, 这也是disable_irq与disable_irq_nosync不同的主要所在.
但是在中断处理函数中调用会发生什么情况呢?
进入中断处理函数前IRQ_INPROGRESS会被__setup_irq设置, 所以程序会一直陷在while循环中, 而此时内核以经被独占, 这就导致系统死掉.
总结:
由于在disable_irq中会调用synchronize_irq函数等待中断返回, 所以在中断处理程序中不能使用disable_irq, 否则会导致cpu被synchronize_irq独占而发生系统崩溃.
1.disable_irq 会禁止给定的中断,而且会等待当前正在执行的中断处理程序完成。disable_irq_nosync(disable_irq函数的非同步版本)会立即返回,这样,使用后者将会更快,但是可能会让你的驱动程序处于竞态下。
2.disable_irq相当于disable_irq_nosync + synchronize_irq,可能忙等待。synchronize_irq会忙等待irq handler执行完成,如果irq handler是被自己这个中断给中断的,怎么等都不会返回。




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值