Search code examples
linux-kernelkernelinterrupttaskletsoftirq

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


In linux Kernel implementation for ARM platform, deferred work in tasklet is added to percpu vec|vec_hi list.

  1. now while returning from ISR execution it goes to address deferred work in softirq and tasklets.
  2. now this deferred work can be taken care of here in interrupt context with IRQs enabled or there are ksoftirq threads that can process it in process context.
  3. same tasklet will be executed on the same CPU as ksoftirq thread is percpu.
  4. I have been seeing that in many books e.g. LDD, Robert Love's book, it's claimed that same tasklet can't be executed on two cores simultaneously?

how? can someone help me with this... If this is so, what am I missing?


Solution

  • 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.