中断线程化,使得高优先级的中断变成了普通的内核线程,和其他程序共用CPU,通过优先级来决定谁能够获取CPU的使用权。将一些不重要的中断改在线程中执行,只要RT任务优先级比中断线程优先级高,就可以优先执行,以此来提高系统的实时性能

传统主线内核默认中断行为

普通硬中断上下文:关闭硬件中断,同时隐式禁止抢占、禁止软中断,中断处理全程在硬中断上下文执行。

为了清晰描述,我用excel画了下面这张图。从图中可以看到,硬中断、软中断、特定的tasklet都不在调度器的管辖范围内,运行在interrupt context中。无论是内核线程还是用户程序,在中断发生时,都需要立刻让出CPU的使用权。在实时系统中,其实很多中断所做的并不是特别重要的工作,或者说,即使有些许延迟,也是无关紧要的。主线内核中的默认中断行为,会严重影响RT任务的执行周期及抖动。

original-kernel-irq

PREEMPT_RT中的中断行为

PREEMPT_RT 默认强制开启线程化中断(threaded interrupts);除带 IRQF_NO_THREAD 标记的中断外,所有中断处理函数都运行在内核线程上下文,不再跑在硬中断上下文。

如下图所示,不重要的硬中断、所有软中断和tasklet都不在运行在interrupt context中,而是作为普通的内核线程,交给调度器,根据调度算法来决定是否可被抢占。换个说法就是,通过提高RT Task的优先级,在PREEMPT_RT kernel中,RT Task可以避免一些中断的干扰(传统内核中的中断,在PREEMPT_RT内核中已经变成了线程)。

preempt-kernel-irq

不会被线程化的中断
IRQF_NO_THREAD 标志的中断仍以原始硬中断方式运行、关硬件中断;

  • IPI 跨处理器中断 主动使用该标志
  • IRQF_TIMERIRQF_PER_CPU 类型中断隐式自带 IRQF_NO_THREAD,不会线程化。

线程化中断的线程属性
开启后,中断交由内核线程执行,调度策略为 SCHED_FIFO,默认优先级 50。

/*
 * Priority of a process goes from 0..MAX_PRIO-1, valid RT
 * priority is 0..MAX_RT_PRIO-1, and SCHED_NORMAL/SCHED_BATCH
 * tasks are in the range MAX_RT_PRIO..MAX_PRIO-1. Priority
 * values are inverted: lower p->prio value means higher priority.
 */

#define MAX_RT_PRIO		100

void sched_set_fifo(struct task_struct *p)
{
	struct sched_param sp = { .sched_priority = MAX_RT_PRIO / 2 };
	WARN_ON_ONCE(sched_setscheduler_nocheck(p, SCHED_FIFO, &sp) != 0);
}

/*
 * Interrupt handler thread
 */
static int irq_thread(void *data)
{
...
	sched_set_fifo(current);
...
}

本作品采用 CC BY-NC-SA 4.0 协议


原文地址: https://www.cveoy.top/t/topic/qGzm 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录