抛弃中断bottom half,使用中断线程吧

4 篇文章 0 订阅
在linux里,中断处理分为顶半(top half),底半(bottomhalf),在顶半里处理优先级比较高的事情,要求占用中断时间尽量的短,在处理完成后,就激活底半,有底半处理其余任务。底半的处理方式主要有soft_irq,tasklet,workqueue三种,他们在使用方式和适用情况上各有不同。soft_irq用在对底半执行时间要求比较紧急或者非常重要的场合,主要为一些subsystem用,一般driver基本上用不上。tasklet和work queue在普通的driver里用的相对较多,主要区别是tasklet是在中断上下文执行,而workqueue是在process上下文,因此可以执行可能sleep的操作。

2.6.30里,在ingo molnar的RT tree里存在有一段时间的interruptthread终于merge到mainline了。此时如果使用request_threaded_irq申请的中断,handler不是在中断上下文里执行,而是在新创建的线程里执行,这样,该handler非常像执行workqueue,拥有所有workqueue的特性,但是省掉了创建,初始化,调度workqueue的繁多步骤。处理起来非常简单。让我们看看这个接口。

int request_threaded_irq(unsigned int irq, irq_handler_t handler, irq_handler_t thread_fn,
                         unsigned long irqflags, const char *devname, void *dev_id)

和request_irq非常类似,irq是中断号, handler是在发生中断时,首先要执行的code,非常类似于顶半,该函数最后会return IRQ_WAKE_THREAD来唤醒中断线程,
一般设为NULL,用系统提供的默认处理。thread_fn,是要在线程里执行的handler,非常类似于底半。 后三个参数基本和request_irq相同。irqsflags新增加了一
个标志,IRQF_ONESHOT,用来标明是在中断线程执行完后在打开该中断,该标志非常有用,否则中断有可能一直在顶半执行,而不能处理中断线程。例如对于
gpio level中断,如果不设置该位,在顶半执行完成后,会打开中断,此时由于电平没有变化,马上有执行中断,永远没有机会处理线程。

下边一个实际例子来说明它的应用。在手机平台中,检测耳机的插入一般是通过耳机插孔中机械变化导致一个baseband gpio的电平的变化,
在该gpio中断里进行耳机插入处理。但是耳机插入一般都有个抖动的过程,需要消抖处理。最简单的办法是在中断发生后,延时一段时间(例如200ms),然后再检
查GPIO状态是否稳定来确定是否有效插入。如果用老的中断方式,不得不用workqueue的方式,你需要在顶半里激活一个delay 200ms的workqueue,然后在workqueue
里检查。用线程化的处理方式,你仅仅需要在thread_fn里sleep 200ms,然后在检查即可。看,事情就这么简单!


handle_IRQ_event函数来逐个执行action链表中用户注册的中断处理函数,它在kernel/irq/handle.c中定义。

do {
379 trace_irq_handler_entry(irq, action);
380 ret = action->handler(irq, action->dev_id);//执行用户注册的中断处理函数

381 trace_irq_handler_exit(irq, action, ret);
382
383 switch (ret) {
384 case IRQ_WAKE_THREAD:
385 /*
386 * Set result to handled so the spurious check
387 * does not trigger.
388 */
389 ret = IRQ_HANDLED;
390
391 /*
392 * Catch drivers which return WAKE_THREAD but
393 * did not set up a thread function
394 */
395 if (unlikely(!action->thread_fn)) {
396 warn_no_thread(irq, action);
397 break;
398 }
399
400 /*
408 if (likely(!test_bit(IRQTF_DIED,
409 &action->thread_flags))) {
410 set_bit(IRQTF_RUNTHREAD, &action->thread_flags);
411 wake_up_process(action->thread);
412 }
413
414 /* Fall through to add to randomness */
415 case IRQ_HANDLED:
416 status |= action->flags;
417 break;
418
419 default:
420 break;
421 }
422
423 retval |= ret;
424 action = action->next; //下一个

425 } while (action);

我们看到在中断处理过程中先执行 用户注册的中断处理函数:action->handler(irq, action->dev_id); 再执行中断线程 wake_up_process(action->thread);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值