中断线程化的意义在于:在 Linux 中,中断具有最高的优先级。不论在任何时刻,只要产生中断事件,内核将立即执行相应的中断处理程序,等到所有挂起的中断和软中断处理完毕后才能执行正常的任务,因此有可能造成实时任务得不到及时的处理。中断线程化之后,中断将作为内核线程运行而且被赋予不同的实时优先级,实时任务可以有比中断线程更高的优先级。
明白原理后对我们程序员来说如何如何注册一个中断线程化的irq呢?
可以参考下面这段code
源码在drivers/thermal/hisi_thermal.c 中的hisi_thermal_probe函数中
ret = devm_request_threaded_irq(&pdev->dev, data->irq,
hisi_thermal_alarm_irq,
hisi_thermal_alarm_irq_thread,
0, "hisi_thermal", data);
if (ret < 0) {
dev_err(&pdev->dev, "failed to request alarm irq: %d\n", ret);
return ret;
}
看看devm_request_threaded_irq的原型
int devm_request_threaded_irq(struct device *dev, unsigned int irq,
irq_handler_t handler, irq_handler_t thread_fn,
unsigned long irqflags, const char *devname,
void *dev_id)
这里的thread_fn就代表中断要执行的代码,其次对中断程序也有要求
static irqreturn_t hisi_thermal_alarm_irq(int irq, void *dev)
{
struct hisi_thermal_data *data = dev;
//核心是关掉irq,并返回IRQ_WAKE_THREAD,这样才会执行thread_fn
disable_irq_nosync(irq);
data->irq_enabled = false;
return IRQ_WAKE_THREAD;
}
static irqreturn_t hisi_thermal_alarm_irq_thread(int irq, void *dev)
{
struct hisi_thermal_data *data = dev;
struct hisi_thermal_sensor *sensor;
int i;
mutex_lock(&data->thermal_lock);
sensor = &data->sensors[data->irq_bind_sensor];
dev_crit(&data->pdev->dev, "THERMAL ALARM: T > %d\n",
sensor->thres_temp / 1000);
mutex_unlock(&data->thermal_lock);
for (i = 0; i < HISI_MAX_SENSORS; i++) {
if (!data->sensors[i].tzd)
continue;
thermal_zone_device_update(data->sensors[i].tzd,
THERMAL_EVENT_UNSPECIFIED);
}
//这里一般返回IRQ_HANDLED
return IRQ_HANDLED;
}
那为什么中断程序要返回IRQ_WAKE_THREAD 才会执行thread_fn呢?
最终处理中断的函数为
irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags)
{
irqreturn_t retval = IRQ_NONE;
unsigned int irq = desc->irq_data.irq;
struct irqaction *action;
record_irq_time(desc);
for_each_action_of_desc(desc, action) {
irqreturn_t res;
trace_irq_handler_entry(irq, action);
//这里会执行irq的回调函数,可以看到只有这里返回IRQ_WAKE_THREAD,才会调用__irq_wake_thread 来运行中断的线程
res = action->handler(irq, action->dev_id);
trace_irq_handler_exit(irq, action, res);
if (WARN_ONCE(!irqs_disabled(),"irq %u handler %pF enabled interrupts\n",
irq, action->handler))
local_irq_disable();
switch (res) {
case IRQ_WAKE_THREAD:
/*
* Catch drivers which return WAKE_THREAD but
* did not set up a thread function
*/
if (unlikely(!action->thread_fn)) {
warn_no_thread(irq, action);
break;
}
//__irq_wake_thread->wake_up_process 来wakeup在调用devm_request_threaded_irq时候为线程建立的thread
__irq_wake_thread(desc, action);
/* Fall through to add to randomness */
case IRQ_HANDLED:
*flags |= action->flags;
break;
default:
break;
}
retval |= res;
}
return retval;
}
中断线程化的意义和如何注册一个有中断线程化的irq
最新推荐文章于 2024-08-13 22:16:23 发布