While understanding the concepts of top halves and bottom halves, I came
across with a question.
Here is my understanding:
Top half and Bottom half executes in interrupt context. The only
difference being that the Bottom half executes with interrupt enabled while
the top half executes with the corresponding irq disabled(Which can still be
overcome by using SA_INTERRUPT
flag).
The question:
Just before return from the top half handler, return_from_intr
is
called. Now the scheduler is invoked and executes the bottom halves if there
are any pending ones.
Since return_from_intr
is called, how can the bottom halves execute in
interrupt context?. It will be in kernel mode rather than the interrupt
mode?
Please correct me if I am wrong.
Bottom halves aren't executed in the interrupt context, which is the entire point of splitting interrupt processing into two halves and moving slower code outside of the ISRs. They're still in the kernel context, though. See this article, for example.
Tasklets and softirqs, the differed portion of interrupt processing, runs on top of software interrupt. Hence they are said to be running on interrupt context(confusingly I would refer this as bottom half context) in which all hardirqs are enabled on all the CPUs(still control is in our hand). Software interrupts may also be disabled if required while processing them using spin_lock_bh().
Work queues, another way of differing interrupt processing, runs in kernel process context. Hence they may block, sleep or can call schedule.
Some assumptions is in your questions are wrong:
- Top half handlers run in interrupt context
- 3 different bottom halves mechanisms exist:
- Softirqs, which run in interrupt context
- Tasklet, which are built on top of softirqs and, therefore, run in interrupt context
- Work queues, which are the only bottom half mechanism run in process context
You may want to refer to the excellent book by Robert Love which explains all these mechanisms.
"Interrupt context" here refers to software-interrupt/softirq context, wherein in_interrupt() returns true, however in_irq() would return false. That is, other softirqs on this core are disabled, but hardware-irqs are enabled.