中断线程化

简介

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

  soft_irq 用在对执行时间要求比较紧急或者非常重要的场合。 taskletworkqueue 在普通的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_fnhandler返回正确值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的参数
posted @ 2022-08-07 20:57  明月时勿余  阅读(349)  评论(1)    收藏  举报