中断线程化的意义和如何注册一个有中断线程化的irq

中断线程化的意义在于:在 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;
}


你可能感兴趣的:(Linux,源码分析)