ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

Linux 中断 request_threaded_irq request_irq

2022-08-31 20:05:05  阅读:172  来源: 互联网

标签:threaded 中断 irq request 线程 进程 执行


 

https://blog.csdn.net/mcsbary/article/details/103728816

总结:
request_threaded_irq:中断处理线程化,很好解决高频率的中断响应,类似异步处理
request_irq:类似于同步处理事务,适合非高频率中断响应。

 

 

https://zhuanlan.zhihu.com/p/151888181

 

Linux 中断处理分为顶半部(top half)和底半部(bottom half),一般要求在顶半部里处理优先级比较高的事情,处理时间应尽量短,在处理完成后就激活底半部,在底半处部理其余任务。底半部的处理方式主要有soft_irq, tasklet, workqueue三种,它们的使用方式和适用情况各有不同。

soft_irq 用在对执行时间要求比较紧急或者非常重要的场合。 tasklet 和 work queue 在普通的driver里用的较多,主要区别是tasklet是在中断环境中执行,而work queue 则是在进程中执行,因此可以使用sleep()。

Linux 中断的优先级比进程高,一旦中断过来普通进程实时进程通通都要给中断处理程序让路,如果顶半部处理任务较多就会对实时进程造成很大的影响,并且这种影响存在较大的不确定性因此难以准确评估。为了解决这些实时性相关问题,Linux RT_PREEMPT 补丁引入了中断线程化的机制。在新的机制中,中断虽然还会打断实时进程,但中断处理程序所执行的操作仅仅是唤醒中断线程,原本的中断服务程序主体放到一个内核线程中延迟执行,这样中断执行的速度就很快也很确定,实时进程被打断后可以迅速再次运行,而中断服务程序会在实时进程挂起之后被系统调度执行。

Linux 2.6.30里,在ingo molnar的RT tree里存在有一段时间的interrupt thread终于merge到mainline了。此时如果使用request_threaded_irq申请的中断,handler 不是在中断环境里执行,而是在新创建的线程里执行,这样该handler非常像执行workqueue,拥有所有work queue的特性,但是省掉了创建、初始化、调度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)

其中,

irq 是中断号,

handler 是在发生中断时首先要执行的处理程序,非常类似于顶半部,该函数最后会返回 IRQ_WAKE_THREAD 来唤醒中断线程。handler 一般设为NULL,用系统提供的默认处理。

thread_fn 是要在线程里执行的处理程序,非常类似于底半部。

后三个参数基本和request_irq相同。

irqsflags 新增加了一个标志IRQF_ONESHOT,用来声明需要在中断线程执行完后才能打开该中断。对于电平有效的中断类型,如果不设置该标志可能会出现死锁情形:CPU 执行完成顶半部代码后会打开中断,此时如果中断信号电平没有变化(中断源在等待CPU发出reset信号),CPU会立刻重复响应该中断,导致永远没有机会进入线程处理,也就永远不会reset该中断。


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

 

中断线程化的反例

有一个项目对实时性要求比较高,于是在linux内核上打了RT_PREEMPT补丁。最终碰到的一个问题是,芯片本身性能不强,CPU资源不足,急需优化。

初步分析

看了下cpu占用率,除了主应用之外,有一个名为irq/38-twi0的进程引起了我们的注意,因为它竟然占据了10%的cpu。

这个irq开头的进程是做什么的呢?原来这是一个被线程化了的中断服务程序,负责处理i2c中断的。这个项目i2c总线上挂载了多个设备,压力是比较大的。

第一个想法是能否减少设备数量或者减低采集频率,但这会影响到应用的算法表现,暂时不考虑。

第二个想法是优化代码,但打开中断服务程序的源码一看,其实现非常简单,基本就只是从硬件寄存器中把接收到的数据取出来而已,看来从这里入手也希望不大。

再仔细想想,这个进程执行的操作这么简单,CPU占用率却这么高,那么主要就是因为其执行的频率过高,每次执行其实都会伴随着进程调度以及上下文切(context switching)换带来的开销,这部分是否可以进行优化呢?

从中断线程化的初衷看,当前这种场景根本就不适用中断线程化。

  1. 这个中断服务程序非常简单,没必要线程化。强行线程化对实时性的改善不大,反而会带来不必要的开销。

2. 这个中断服务程序非常关键,其中采集的数据的实时性也非常重要,不应该被延迟执行。中断切换回实时进程后,实时进程依赖这些数据,还是要等这个进程把数据取出。

解决

解决方式很简单,对于这个具体的中断,取消线程化,让它变回一个朴素的中断。中断线程化的机制虽好,也要分情况来使用,不然反而会造成系统的巨大负担。

代码改动是在request_irq时,传入IRQF_NO_THREAD标志,即可避免这个中断被线程化。

实际做改动还要注意,RT_PREEMPT使用rt_mutex代替传统的禁用抢占的spin_lock,因此如果需要用真正的spin_lock,需要使用raw_spin_lock_t

在这个具体的例子中,中断大概为一万两千次/秒,取消线程化之后,CPU占用率下降了约10%,效果显著。

标签:threaded,中断,irq,request,线程,进程,执行
来源: https://www.cnblogs.com/sinferwu/p/16644341.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有