Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can ISRs migrate to other CPUs when preempted?

In older versions of the Linux kernel, the interrupt service routines (ISRs) for hardware IRQs in an SMP system were executed on the CPU where they started, from the beginning to the end. If preempted by some other code, an ISR would resume afterwards on the same CPU.

But in recent kernels, most of the ISRs should be executed in the context of special kernel threads by default (http://lwn.net/Articles/433854/). The "ordinary" kernel threads can migrate to another CPU when preempted. So the question is, can ISRs also do such things now, for whatever reason?

Note that I am not talking about CPU affinity of the IRQs and IRQ balancing between the processors. I am curious about the situation when an interrupt handler is already running but is preempted.

That is, assume an ISR has already started executing on CPU #1. Now it is preempted by some higher priority code. When the latter has done its work, the ISR resumes execution - but on CPU #2. Are such situations possible?

The pointers to the relevant docs, discussions, etc., are always welcome.

like image 893
Eugene Avatar asked Oct 25 '22 11:10

Eugene


1 Answers

The ISR threads get the same affinity as the ISR routines, so in the case of preemption, the ISR thread will not reschedule to an arbitrary CPU.

Also, the behavior of forcing ISRs to become threads is not enabled by default according to the information in the link you provided. It is conditioned by the threadirqs command line option. The handling of the command line options takes care of ISR threads in a way that traditional ISRs would not need to care about the rescheduling. According to the following code in kernel/irq/manage.c, preemption is disabled for these threads:

/*
 * Interrupts which are not explicitely requested as threaded
 * interrupts rely on the implicit bh/preempt disable of the hard irq
 * context. So we need to disable bh here to avoid deadlocks and other
 * side effects.
 */
static void
irq_forced_thread_fn(struct irq_desc *desc, struct irqaction *action)
{
        local_bh_disable();
        action->thread_fn(action->irq, action->dev_id);
        irq_finalize_oneshot(desc, action, false);
        local_bh_enable();
}
like image 173
Dan Aloni Avatar answered Nov 13 '22 01:11

Dan Aloni