Interrupt handler and process scheduler - linux

I know in Linux kernel, there is a context switching, when an hardware interrupt occurs.
I want to know one thing:
1) If I am executing interrupt handler, will my process scheduler still be scheduling
processes or it will stop scheduling until interrupt handler is completed.

Interrupt handlers (smart ones) are split in two parts:
A top-half where interrupts are disabled, no scheduling. A high-priority task is then scheduled for later execution: The bottom-half.
A bottom-half to complete the interrupt handling.
A nice book 'Linux Device Driver: Top and Bottom Halves' contains more information.

Related

x86 how does Linux signal interrupt instruction stream

How does a Linux signal lead to the instruction stream of the X86 processor getting interrupted? So what CPU facility is used?
You have synchronous and asynchronous interrupts.
Synchronous interrupts are for issues like page faults, exceptions etc. Problems that are caused by the instructions that are executing on the CPU.
Asynchronous interrupts are from an IPI from the LAPIC, timer interrupt or for an interrupt picked up by the I/O-APIC and routed to the right LAPIC which then interrupts the processor. So these are external events.
But which X86 mechanism does the Signal use to interrupt the instruction stream and start processing the signal handler.
It isn't an asynchronous interrupt AFAIK because interrupts are handled within the kernel and signals in user-space. But its behavior is very similar to that of an asynchronous interrupt.
The kernel has to deliver a signal to user-space. You're right that that doesn't just happen on its own in hardware. That's why signal handling can respect the user-space red-zone, sigaltstack, and default actions if there's no handler registered.
As soon as the kernel has control, it can deliver the signal to user-space (or do the default action of ignoring it or killing the process).
If the signal was sent by a process running on another core, to a process running on this core, then probably it's delivered to user-space from an IPI handler, or else just at the next timer interrupt or system call that gives the kernel a chance to check for a pending signal.
When the IPI interrupt handler is preparing to return to user-space, it notices that there's a pending interrupt for the process that it's about to return to. (Either with a special case for one type of IPI, or by running the scheduler since we're in the kernel anyway). Instead of using iret to return to the interrupt frame pushed by hardware for the async interrupt, the kernel instead can iret to the address of the user-space signal handler.
The whole point of using an IPI (if that's what Linux even does) is to transfer control to the kernel sooner, instead of just waiting for it to notice the pending signal the next time it calls schedule().
If the process the signal is sent to isn't currently running on any core, then it either wakes the process up if there's a free CPU, or the signal just sits there for that task until the scheduler on some core decides to run it on this core. At that point it will notice and deliver the pending signal.

What will happen to the state of the tasklet when tasklet is running and hardware interrupt triggered?

What will happen to the state of the tasklet when tasklet is executing and hardware interrupt triggered in the middle of tasklet execution ?
Tasklet are the bottom half. They run in softirq context and not in hardware interrupt context. So hardware interrupts are always enabled. When hardware interrupts is triggered while executing tasklets then it will interrupt the tasklet. Then top half is run on the respective IRQ stack and acknowledge the interrupt. This behavior is especially useful with interrupt handlers, where the hardware interrupt must be managed as quickly as possible, but most of the data management can be safely delayed to a later time. Actually, a tasklet, just like a kernel timer, is executed (in atomic mode) in the context of a soft interrupt, a kernel mechanism that executes asynchronous tasks with hardware interrupts enabled.
Check tasklet_schedule function.
It will save the state of the interrupt system and restore interrupts to their previous state and return after do_softirq operation.
Tasklets run in interrupt context. So code in tasklets should not sleep (or be interrupted). If the tasklet is interruped by an interrupt, your system crashes. To prevent interrupts while running tasklet you have to prevent the interrupts by using spinlock_irq_save()

How is interrupt context "restored" when a interrupt handler is interrupted by another interrupt?

I read some related posts:
(1) From Robert Love: http://permalink.gmane.org/gmane.linux.kernel.kernelnewbies/1791
You cannot sleep in an interrupt handler because interrupts do not have a backing
process context, and thus there is nothing to reschedule back into. In other
words, interrupt handlers are not associated with a task, so there is nothing to
"put to sleep" and (more importantly) "nothing to wake up". They must run
atomically.
(2) From Which context are softirq and tasklet in?
If sleep is allowed, then the linux cannot schedule them and finally cause a
kernel panic with a dequeue_task error. The interrupt context does not even
have a data structure describing the register info, so they can never be scheduled
by linux. If it is designed to have that structure and can be scheduled, the
performance for interrupt handling process will be effected.
So in my understanding, interrupt handlers run in interrupt context, and can not sleep, that is to say, can not perform the context switch as normal processes do with backing mechanism.
But a interrupt handler can be interrupted by another interrupt. And when the second interrupt handler finishes its work, control flow would jump back to the first interrupt handler.
How is this "restoring" implemented without normal context switch? Is it like normal function calls with all the registers and other related stuff stored in a certain stack?
The short answer is that an interrupt handler, if it can be interrupted by an interrupt, is interrupted precisely the same way anything else is interrupted by an interrupt.
Say process X is running. If process X is interrupted, then the interrupt handler runs. To the extent there is a context, it's still process X, though it's now running interrupt code in the kernel (think of the state as X->interrupt if you like). If another interrupt occurs, then the interrupt is interrupted, but there is still no special process context. The state is now X->first_interrupt->second_interrupt. When the second interrupt finishes, the first interrupt will resume just as X will resume when the first interrupt finishes. Still, the only process context is process X.
You can describe these as context switches, but they aren't like process context switches. They're more analogous to entering and exiting the kernel -- the process context stays the same but the execution level and unit of code can change.
The interrupt routine will store some CPU state and registers before enter real interrupt handler, and will restore these information before returning to interrupted task. Normally, this kind of storing and restoring is not called context-switch, as the context of interrupted process is not changed.
As of 2020, interrupts (hard IRQ here) in Linux do not nest on a local CPU in general. This is at least mentioned twice by group/maintainer actively contributing to Linux kernel:
From NAPI updates written by Jakub Kicinski in 2020:
…Because normal interrupts don't nest in Linux, the system can't service any new interrupt while it's already processing one.
And from Bootlin in 2022:
…Interrupt handlers are run with all interrupts disabled on the local CPU…
So this question is probably less relevant nowadays, at least for Linux kernel.

How Tasklets works?

Does interrupts are disabled while tasklets are being processed since they should run in interrupt context.If they are disbled while a tasklet is being processed then what is the point of calling them bottom halve mechanism since it is same case as top of where the interrupts are disabled.
Or is it like tasklets will be useful only on multi processor system where the interrupts are generated on one processor and the corresponding tasklet is scheduled on another processor with interrupts being disbled on another processor when the tasklet is running.
Please clarify.
Linux divides interrupt processing in two parts:
First, you handle the interrupt request (IRQ) in as simple a manner as possible, doing as little as you can, and scheduling a softirq/tasklet to do the heavier part of the processing.
Then, the softirq/tasklet gets scheduled, and the heavy processing starts.
The contexts in Linux are:
NMI context
hardirq context: the first part of interrupt processing above.
softirq context: the second part of interrupt processing above.
interrupt context: any of the above.
process/user context: running on behalf of a process, e.g: due to a syscall. The opposite of interrupt context.
atomic context: interrupt context, or in process context in a section of code that must be atomic (cannot be interrupted), e.g: because we have taken a spinlock.
Interrupts are not disabled while running a tasklet. Further invocations of the same tasklet are.

Can an interrupt handler be preempted?

I know that linux does nested interrupts where one interrupt can "preempt" another interrupt, but what about with other tasks.
I am just trying to understand how linux handles interrupts. Can they be preempted by some other user task/kernel task.
Reading Why kernel code/thread executing in interrupt context cannot sleep? which links to Robert Loves article, I read this :
some interrupt handlers (known in
Linux as fast interrupt handlers) run
with all interrupts on the local
processor disabled. This is done to
ensure that the interrupt handler runs
without interruption, as quickly as
possible. More so, all interrupt
handlers run with their current
interrupt line disabled on all
processors. This ensures that two
interrupt handlers for the same
interrupt line do not run
concurrently. It also prevents device
driver writers from having to handle
recursive interrupts, which complicate
programming.
So AFIK all IRQ's are disabled while within the interrupt handler, therefore it cannot be interrupted!?
Simple answer: An interrupt can only be interrupted by interrupts of higher priority.
Therefore an interrupt can be interrupted by the kernel or a user task if the interrupt's priority is lower than the kernel scheduler interrupt priority or user task interrupt priority.
Note that by "user task" I mean user-defined interrupt.

Resources