Today, let's talk about IRQL, which is a nightmare for new users. Think about how much bsod is caused by IRQL mismatch. This is also one of the most popular sputation points for * nix kernel developers. You don't have this concept in Linux, and we are not very well-behaved? Sometimes I can get some blank space and ask the same question: Is it Mao? Mao must have this thing! Later I figured it out.
Let's talk about passive level and interrupt level first. Passive level is a common level and has the lowest priority. All user-state threads and most kernel-state threads run at this level. Interrupt level is the running level of the interrupt service routine. These two are not easy to understand. Almost all OS tutorials have warned us to interrupt service routines as quickly as possible and cannot be preemptible by other threads, you cannot manually hand over the operation permission (sleep ). The interrupt in the NT kernel does not belong to its own stack. It will preemptively use the stack of the current running thread. Even if the user who gets the break is unlucky, the Linux kernel seems to look at the configuration, when the stack size is 4 K, it is also used by others. If the interrupted service routine can be preemptible (that is, swapped out), these contexts will exist on the top of others' stacks. Consider such a situation: the interrupted service routine grabbed the stack of thread T1, and half of the run time was occupied by thread T2. The unlucky rush of T2, the new top bit is exactly T1, and this is the problem. T1 is not preemptible because of thread switching. It is interrupted, and the context of T1 is not retained before the interruption is switched out. Therefore, recovery becomes an impossible task. To prevent such a situation, the service interruption routine must not be preemptible by other threads. It does things on the T1 stack, cleans up the stack, and returns it to T1 for further operation, it seems that T1. It is easy to do this. You only need to disable all other interruptions before running the interrupt service routine. In fact, Linux does. (If I am wrong, please tell me ), however, the designers of the NT kernel think a little more about it. They think it is too violent to shut down all the interruptions. Even if the names are called interruptions, there must be priorities, power outages are much more urgent than hard drive interruptions. So they decided to give this kind of ability to seize others in different levels, (hardware) interruption at the interrupt level, there are N levels above it, even if the interrupt service routine is running, these n high-level tasks can still rob people of eggs. For the complete permission level, Google.
Now let's talk about APC level and DPC level. These two levels have nothing to do with the architecture. They are purely related to the implementation mechanism of NT. APC provides a method to allow a thread to intrude into other threads and delegate other threads to do what they want, such as when the process is about to exit, the thread that initiates the exit action inserts an APC into all threads in the process, and the APC completes the process. For example, the completeroutine we have been talking about in the last two times is also completed by the APC mechanism. You can think of APC as something similar to * nix signal. DPC is similar to APC in that it entrusts some work to others, but APC is attached to the thread, while DPC is independent, and each CPU has a DPC queue, the DPC queue will be checked before thread scheduling. If it is not empty, the DPC will be checked first and then the thread will be picked. This concept is very similar to the lower half of Linux. The general idea is that the shorter the interrupt service routine, the better. How can we delay processing other things. The NT kernel has a clock that interrupt once and sends out a DPC. The DPC is used up to check whether the current running thread has used up its own time slice. If it is used up, then let it enter the Wait Status and pick individual threads for execution. So we can see that the thread scheduling in the NT kernel is running at the DPC level. If something running at the DPC level needs to be sleep, the deadlock will happen: I am going to bed, I voluntarily handed over the running permission --> the scheduler tried to run it and found that its level is also DPC level --> it cannot be preemptible. People of the same level cannot compete with each other. City Management can rob small traders, but it is enough to rob the demolition team. --> You got a deadlock !.
In general, passive level and interrupt level are obvious and easy to understand. APC level and DPC level are introduced by the NT implementation mechanism. In fact, they are annoying but useful. Looking back, is there really no IRQL concept in Linux? Not necessarily, passive level and interrupt level are inevitable. The lower half can be regarded as DPC, and the signal can be regarded as APC. The first three of the four levels are consistent with the NT kernel, only APC and signal are different. Therefore, we say that the kernel is becoming more and more consistent with the development philosophy.