中断线程化
简介
Linux 中断处理分为顶半部(top half)和底半部(bottom half),一般要求在顶半部里处理优先级比较高的事情,处理时间应尽量短,在处理完成后就激活底半部,在底半处部理其余任务。底半部的处理方式主要有soft_irq, tasklet, workqueue三种,它们的使用方式和适用情况各有不同。
soft_irq 用在对执行时间要求比较紧急或者非常重要的场合。 tasklet 和 workqueue 在普通的driver里用的较多,主要区别是tasklet是在中断环境中执行,而workqueue则是在进程中执行,因此可以使用sleep()。
Linux中断的优先级比进程高,一旦中断过来普通进程实时进程通通都要给中断处理程序让路,如果顶半部处理任务较多就会对实时进程造成很大的影响,并且这种影响存在较大的不确定性因此难以准确评估。为了解决这些实时性相关问题,Linux RT_PREEMPT补丁引入了中断线程化的机制。在新的机制中,中断虽然还会打断实时进程,但中断处理程序所执行的操作仅仅是唤醒中断线程,原本的中断服务程序主体放到一个内核线程中延迟执行,这样中断执行的速度就很快也很确定,实时进程被打断后可以迅速再次运行,而中断服务程序会在实时进程挂起之后被系统调度执行。
Linux 2.6.30里,此时如果使用request_threaded_irq申请的中断,handler不是在中断环境里执行,而是在新创建的线程里执行,这样该handler非常像执行workqueue,拥有所有workqueue的特性,但是省掉了创建、初始化、调度workqueue的步骤,处理起来非常简单。
接口介绍
接口如下,也有devm_前缀的自动资源管理版本:
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触发时运行的程序(中断上下文)
如过为NULL则如下
/* * Default primary interrupt handler for threaded interrupts. Is * assigned as primary handler when request_threaded_irq is called * with handler == NULL. Useful for oneshot interrupts. */ static irqreturn_t irq_default_primary_handler(int irq, void *dev_id) { return IRQ_WAKE_THREAD; } -
handler_fn为handler返回正确值IRQ_WAKE_THREAD时在一个新的内核线程中调用的函数(不在中断上下文)
-
irqflags 中断类型标志
-
devname 声明设备的ascii名称
-
dev_id 传递回处理函数的cookie
使用示例
这里列出电容触摸芯片gt911的驱动程序中对中断的申请部分
static int goodix_request_irq(struct goodix_ts_data *ts)
{
return devm_request_threaded_irq(&ts->client->dev, ts->client->irq,
NULL, goodix_ts_irq_handler,
ts->irq_flags, ts->client->name, ts);
}
解析:
- handler为NULL代表所有的处理代码均放到线程处理函数handler_fn中执行
- 最后一个参数ts则将驱动设备私有数据传递给独立线程中断处理函数handler_fn的参数
本文来自博客园,作者:明月时勿余,转载请注明原文链接:https://www.cnblogs.com/myswy/p/16559864.html

浙公网安备 33010602011771号