4. Interrupt handler
The interrupt handler in Linux is very unique. Its interrupt handler is divided into two parts: the upper half (tophalf) and the lower half (bottom half). The reason why there are upper and lower halves is entirely due to the efficiency of interrupt processing.
The function of the upper half is "Registration Interruption". When an interrupt occurs, it hangs the lower half of the interrupt routine in the device driver into the lower half of the device's execution queue, and then it's fine - waiting for a new interrupt to arrive. In this way, the top half will be executed quickly, and he can accept more interruptions generated by the equipment she is responsible for. The reason why the upper part is faster is that it completely masks interrupts. If it does not finish executing, other interrupts cannot be processed in time and can only wait until the interrupt handler is executed. Therefore, to service and process as many interrupts generated by the device as possible, the interrupt handler must be fast.
However, the processing of some interrupt events is more complicated, so the interrupt handler must spend a little more time to complete the thing. But how to resolve the contradiction of completing complex processing in a short time? At this time, Linux introduced the concept of the lower half. The biggest difference between the lower half and the upper half is that the lower half is interruptible, while the upper half is uninterruptible.
The lower half does almost everything the interrupt handler does, because the upper half just queues the lower half to the interrupt processing queue of the device they are responsible for, and then doesn't care about anything. The lower part is generally responsible for observing the device to obtain event information that generates interrupts, and performing corresponding processing based on this information (usually obtained by reading the registers on the device). If there are times when the second half doesn't know what to do, he uses the famous ostrich algorithm to solve the problem - to put it bluntly, he ignores the event.
Since the lower half is interruptible, if other devices are interrupted while it is running, the lower half can be temporarily interrupted. Wait until the upper half of that device is finished running, and then run it again. . But one thing you must pay attention to is that if a device interrupt handler is running, no matter whether it is running the upper half or the lower half, as long as the interrupt handler has not finished processing, new interrupts generated by the device during this period will Interrupts will be ignored. Because interrupt handlers are not reentrant, the same interrupt handler cannot be executed in parallel.
Before Linux Kernel 2.0, interrupts were divided into fast interrupts and slow interrupts (we will not talk about pseudo-interrupts here). The lower half of the fast interrupt is also uninterruptible, which can ensure that it executes faster. However, as the hardware level continues to rise, there is no difference in the running speed of fast interrupts and slow interrupts. Therefore, in order to improve the efficiency of interrupt routine transaction processing, starting from Linux kernel 2.0, all interrupt handlers are in the form of slow interrupts. --Their lower half can be interrupted.
However, in the second half, you can also mask interrupts - if a certain piece of code cannot be interrupted. You can use cti, sti or save_flag, restore_flag to realize your idea. As for their usage and differences, please refer to the interrupt processing section of the designated reference book in this article.
For further details, please refer to the reference book specified in this article. I will not go into details here. It is not my purpose to introduce the details in detail. My purpose is to organize the concepts.
5. Set the interrupt flag bit
When processing an interrupt, the interrupt controller will block the device that originally sent the interrupt until the last interrupt she sent has been processed. Therefore, if the device that sent the interrupt sends another interrupt during interrupt processing, the interrupt will be lost forever.
The reason why this happens is because the interrupt controller cannot buffer interrupt information, so if a new interrupt arrives before the current interrupt is processed, it will definitely lose the new interrupt. However, this defect can be solved by setting the "set interrupt flag" (sti) on the main processor (CPU), because the main processor has the function of buffering interrupts. If "set interrupt flag bit" is used, then the sti function can be used to service the previously masked interrupt after the interrupt is processed.
The above is the in-depth analysis of Linux device driver interrupts (1) (2). For more related content, please pay attention to the PHP Chinese website (www.php.cn)!