static int __init irqpoll_setup(char *str)
{
#ifdef CONFIG_PREEMPT_RT
pr_warn("irqpoll boot option not supported w/ CONFIG_PREEMPT_RT\n");
return 1;
#endif
irqfixup = 2;
printk(KERN_WARNING "Misrouted IRQ fixup and polling support "
"enabled\n");
printk(KERN_WARNING "This may significantly impact system "
"performance\n");
return 1;
}
__setup("irqpoll", irqpoll_setup);
先看下面一个interrupt的流程, 然后解释noirqdebug 存在的意义.
如果 noirqdebug 为 true, 那么 irqpoll_setup 的存在是 no value !
Linux 内核中没任何模块能绝对“独立”,相互的关系是绝对的,但是独立是相对的.
/*
* 一 : 先来看 interrupt 到底是什么
* 1 : 中断是响应外部硬件设备的一个机制 (包括时钟中断)
* 例如 :
* 时钟中断中更新task的vruntime 、cfs->min_vruntime 以及查看能否抢占 (它委托给一个函数来实现 : entity_tick())
* 2 : 中断是系统中的一个事件(即一个Event)
* (具体的可参见 Intel manual .)
*
* ok !
*
* Force interrupt threading 后,它就成为了一个优先级为50的实时进程,可以被更高优先级的进程抢占了,
*
* 😄哈哈,interrupt终于被拉下了神坛, 也就是说中断可以延迟被执行了.
*
* 如果这个isr中要获取的数据实时性很高,不能被延迟执行,那么就保留原来朴素的中断.即: 反线程化.
*
* 那么既然是一个进程了,那么workqueue也是进程 它们有什么样的异同呢.
* 当然有异同了,且大大的异同,
* 比如说 调度策略,一个是 SCHED_FIFO 一个是SCHED_NORMAL, workqueue靠边站,瘦死的骆驼也比你workqueue大 !
*/
irqreturn_t handle_irq_event_percpu(struct irq_desc *desc)
{
/*
原来的code,这里暂且不讲,让我们专注于 PREEMET_RT
*/
irqreturn_t retval;
unsigned int flags = 0;
/*
* 获取 pt_regs.
* ok, 什么是 pt_regs, 这里为什么要获取它
* 哈哈😄 别忘记中断现场保存在哪里的, 这里要用到了.
* ok,我们把保存中断现场的那段code拿出来,看一下.
*/
struct pt_regs *regs = get_irq_regs();
u64 ip = regs ? instruction_pointer(regs) : 0;
retval = __handle_irq_event_percpu(desc, &flags);
#ifdef CONFIG_PREEMPT_RT
desc->random_ip = ip;
#else
add_interrupt_randomness(desc->irq_data.irq, flags, ip);
#endif
if (!noirqdebug)
note_interrupt(desc, retval);
return retval;
}
struct pt_regs {
union {
struct user_pt_regs user_regs;
struct {
/*
* X0 X1 .... X20 X30 寄存器.
* SP寄存器
* PC寄存器
* PSTATE 寄存器.
*/
u64 regs[31];
u64 sp;
u64 pc;
u64 pstate;
};
};
u64 orig_x0;
#ifdef __AARCH64EB__ /* 大端字节序 */
u32 unused2;
s32 syscallno;
#else
s32 syscallno;
u32 unused2;
#endif
u64 sdei_ttbr1;
u64 pmr_save;
u64 stackframe[2];
u64 lockdep_hardirqs;
u64 exit_rcu;
};