Exactly When Tasklet Runs After It Is Schedule by Isr

Tasklets Bottom half Scheduling

Each CPU has queues for scheduled (high-priority and normal) tasklets.

When a CPU is about to return to user space from an interrupt or from a system call, it checks for scheduled tasklets, and executes them.
The same checks are done again after a tasklet has finished.
(If there are too many scheduled tasklets, they are not all executed at once, but moved into a kernel thread, ksoftirqd; but the principle stays the same.)

Therefore, a tasklet will never interrupt another tasklet, but a high-priority tasklet will be executed before any scheduled 'normal' tasklets.

why same TASKLET can't execute on two core simultaneously?

It's true. While the tasklet can be scheduled (i.e. tasklet execution requested) on any number of CPUs, it will only be executed on one.

The reason for this is I believe to simplify the development model: to make it easier to implement what is essentially an interrupt handler without needing to worry about races due to simultaneous execution on multiple processors -- and while not disabling other interrupts. (Obviously there are still many other opportunities for races that a driver developer needs to be aware of, but these are among the most difficult to solve.)

If you're asking about the implementation, it's actually pretty simple. In tasklet_action, tasklet_trylock is called. It uses the guaranteed-atomic function test_and_set_bit to set the TASKLET_STATE_RUN bit. This can only succeed on one processor. Hence, all other processors are prevented from executing the tasklet until the bit has been cleared -- which is only done by the processor that set it after the tasklet has completed.

EDIT:

Clarifying: calling tasklet_schedule on any number of CPUs (prior to execution) results in the tasklet being executed exactly once: on the first CPU that made the call. The same mechanism (test_and_set_bit) ensures that if the tasklet has already been scheduled on some other CPU but has not yet been executed, it will not be added to the tasklets-to-run queue on the later CPU (and hence won't be executed on the later CPU at all).

On the other hand, if it has already begun executing on the first CPU, the TASKLET_STATE_SCHEDULE bit will have been cleared (and hence may be set again), and so another call to tasklet_schedule ensures that the tasklet will eventually be re-executed on the later CPU, but not until after it has run to completion on the first CPU.

Preemption among SOFTIRQ context

Perhaps you have confused between SOFTIRQ and HARDIRQ. Softirq in Linux kernel is the "bottom_half" in IRQ processing, which is scheduled by the task scheduler for execution to handle delayed IRQ processing. And during this processing, it can potentially handle multiple delay IRQ processing, say IRQ A and IRQ B in your case.

But if any IRQ enters into the system, it will trigger the ISR handler, and there is no immediately triggering of any SOFTIRQ, only being scheduled for later processing, not "invoke" as your wording says. (ie, all hardware IRQ handler are not supposed to call raise_softirq(), but schedule a handler for IRQ processing)

So in summary, for your scenario:

After ISR B have ended, it may submit SOFTIRQ B for later processing - but it is NOT calling raise_softirq(). But since SOFTIRQ A have been intercepted half-way, after any hardware interrupt it will continue the last tasks before, and so SOFTIRQ A will execute to completion.

To elaborate on raise_softirq() internal, which call raise_softirq_irqoff():

inline void raise_softirq_irqoff(unsigned int nr)
{
__raise_softirq_irqoff(nr);

/*
* If we're in an interrupt or softirq, we're done
* (this also catches softirq-disabled code). We will
* actually run the softirq once we return from
* the irq or softirq.
*
* Otherwise we wake up ksoftirqd to make sure we
* schedule the softirq soon.
*/
if (!in_interrupt())
wakeup_softirqd();
}

As the comment goes, if you are inside softirq A and IRQ B comes in, IRQ B processing will end - to be re-run after it finishes the current SOFTIRQ A.

To emphasize that all hardware does not call "raise_softirq()", a search of linux kernel yield the following result (none is from hardware, which is from the "drivers" branch):

Sample Image

And in the networking IRQ handler - the napi_schedule() is called. (In general search for "sched" inside all drivers IRQ handler). The following is from drivers/net/usb/r8152.c:

Sample Image



Related Topics



Leave a reply



Submit