In this blog post, I thought I would attempt to explain what are DPCs.
DPCs are a type of software interrupt, which is used to form a type of synchronization within the kernel, DPCs are only active the current IRQL level for the thread is at IRQL Level 2 (DISPATCH_LEVEL).
We can use the !irql extension to gather what the IRQL level is for the current thread.
DPCs can be used to give device drivers routines higher priority over other tasks, by sending a DPC request to the kernel, which then creates a DPC object for the device driver; the DPC object is then added to the DPC queue. DPCs are also used for thread dispatching.
This DPC object is only visible to the kernel, and will contain the address for the function which will need to be called when the kernel begins to process the DPC queue. Each process has it’s own DPC queue, and each DPC request has it’s own set priority, by default this priority is medium, however, the device driver can change it’s priority within the queue. High priority DPCs are processed first, then medium and then low priority DPCs.
All the DPCs queued will be executed until the queue is empty, or a higher priority interrupt occurs. Typically, the routine used for completing the DPC queue is nt!KiRetireDpcList.
We can view the number of queued DPCs and the priority for each DPC object with the !dpcs extension, we can specify the processor using the processor number, or just type !dpcs to gain the DPC queue for all the processors.
DPCs and Processors
In usual circumstances, the DPC queue is processed when the IRQL level is 2, along with a software interrupt (nt!KiDispatchInterrupt), but this only occurs if the DPC is targeted at the current processor (the processor with the Interrupt Service Routine), and the DPC has a high priority, otherwise it is queued until the number of allowed queued DPCs raises above the threshold.
On the other hand, if a DPC is targeted at different CPU (different to the processor with the ISR), and the currently waiting DPCs have high or medium priority, then a Inter Processor Interrupt (IPI) is sent to the targeted CPU to process it’s DPC queue, although this can only occur if the CPU is idle. The !ipi extension can be used to investigate the IPI state for a certain processor or the all the processors.
If the DPCs within the queue have low priority, and then the DPCs are queued until the threshold is met like before.