Interrupt processing is divided into two parts: the interrupt handler is the upper half, it receives an interrupt, executes immediately, but only does the work with strict time limits, while another part called the lower half mainly does the work that is allowed to be done later. This second half is the focus of today.
The task of the lower half is to perform tasks that are closely related to interrupt processing but which interrupt the native of the handler. The best thing of course is that the interrupt handler will hand over all the work to the lower half and do nothing. Because we always want the interrupt handler to return as quickly as possible. However, the interrupt handler is destined to complete part of the work. Unfortunately, there are no strict rules as to which part of the task should be completed, in other words, this decision is entirely done by a drive engineer like us. Remember, the interrupt handler executes asynchronously, and in the best case it locks the current in-line disconnection, so the smaller the interrupt handler, the better. Of course, there is no rule without experience and lessons:
1. If a task is very sensitive to time, it is a good choice to tell me or put it in an interrupt handler. 2. If a task is related to hardware, or put it in an interrupt handler to execute it. 3. If a task is to ensure that it is not interrupted by other interruptions (especially the same interrupt), put it in the interrupt handler. 4. All other tasks, unless you have a better reason, all of them to the lower half of the execution. |
In short, a word: The faster the interrupt handler executes, the better.
We always say the next half will be executed in the future, then what is the concept of the future. Unfortunately, this is only relative to the immediate. The lower half and need to specify a specific time, just put the task a little bit, so that they are not too busy in the system and interrupt recovery after the execution. Usually the lower half executes immediately when the interrupt handler is returned, and the key is to allow all interrupts when they are run.
The upper half of the can only be done through an interrupt handler, and the lower half is implemented in a number of ways. The mechanisms used to implement the lower half are composed of different interfaces and subsystems respectively. The earliest is "bottom half", which is also known as "BH", which provides a simple interface, provides a static creation, a list of 32 bottom half, and the upper half identifies which bottom executable by one of the 32-bit integers. Each BH is synchronized globally, and does not allow any two bottom half to execute simultaneously, even if it is part of a different processor. This approach is easy to use but not flexible, but has a performance bottleneck. In order to need a better way. The second method, task queue (queues). The kernel defines a set of queues. Each of these queues consists of a list of functions that are waiting to be called. Depending on where they are in the queue, these functions are executed at some point, and the driver can register their lower half to the appropriate queue as needed. This method has been good, but still not flexible enough, it can not replace the entire BH interface. For some subsystems with higher performance requirements, such as the network part, it is not competent. In the 2.3 development version, soft interrupts (Softirqs) and Tasklet are introduced, and the soft interrupts and the soft interrupts (software interrupts) mentioned in the implementation of system calls are not the same concept. Soft interrupts and Tasklet can completely replace the BH interface if they need not be considered compatible with previously developed drivers. A soft interrupt is a set of statically defined lower-half interfaces, 32 of which can be executed on all processors at the same time----even if two types are identical. Task is a flexible, dynamic creation of the lower half of the implementation mechanism based on soft interrupt implementation. Two different types of tasklet can be executed concurrently on different processors, but tasklet of the same type cannot be executed concurrently. Tasklet is actually a product of finding a balance between performance and ease of use. Soft interrupts must be statically registered during compilation, while Tasklet can be dynamically registered through code. Now it's all 2.6 cores, let's say something new, the linux2.6 kernel provides three different forms of the lower half implementation mechanism: Soft interrupts, tasklets, and working pairs, which are described in turn. At this point, some people may think of the concept of the timer, the timer is indeed the case, but the timer provides a precise delay time, we are not so here, so put down, we later talk about the timer. OK, let me start with a detailed mechanism:
1. Soft interruption In fact, soft interruption is not used much, but is behind the tasklet more, but Tasklet is implemented through soft interrupt, soft break code is located in/kernel/softirq.c. Soft interrupts are statically allocated during compilation and are represented by the softirq_action structure, which is defined in Linux/interrupt.h:
2 |
void (*action) (struct softirq_action *); Functions to be executed |
3 |
void *data; Parameters passed to the function |
The KERNEL/SOFTIRQ.C defines an array that contains 32 structures:
1 |
static struct softirq_action softirq_vec[32] |
each registered soft interrupt occupies one of the array, so there may be a maximum of 32 soft interrupts, which cannot be changed dynamically. Since most drivers use Tasklet to implement their lower half, the current kernel uses only 6. In the soft interrupt structure above, the first is the soft interrupt handler, the prototype is as follows: