In the semiconductor and hardware world, timing is everything. While previous articles focused on memory safety, this one deals with responsiveness.
The Bug Check 0x133: DPC_WATCHDOG_VIOLATION occurs when the system detects a single Deferred Procedure Call (DPC) running for an excessive amount of time, or when the cumulative time spent at DISPATCH_LEVEL exceeds a threshold. Essentially, one processor is “stuck,” preventing the OS from scheduling other critical tasks.
1. The DPC and Interrupt Architecture
To understand this crash, we must understand how Windows handles hardware.
- ISR (Interrupt Service Routine): High priority, very short. It tells the hardware “I hear you” and schedules a DPC.
- DPC (Deferred Procedure Call): Lower priority than an ISR but still runs at
DISPATCH_LEVEL($IRQL = 2$). It does the “heavy lifting” (like processing network packets or disk I/O).
The Golden Rule of Kernel Dev: Never block, sleep, or run long loops in a DPC. If a DPC runs too long, the Windows “Watchdog” timer barks, and the system bites with a BSOD.
2. Real Use Case: The Busy-Wait Loop
Scenario: A new PCIe driver works fine under light load, but during heavy stress tests, the system freezes for a second and then crashes with 0x133.
Step 1: The Watchdog Parameters
Run !analyze -v. For 0x133, Parameter 1 is critical:
- Arg1 = 0: A single DPC exceeded the time limit.
- Arg1 = 1: The cumulative time spent at
DISPATCH_LEVELwas too high.
Step 2: Finding the “Hog”
If Arg1 is 0, the debugger usually points directly to the offender. We use the !dpc command to see what’s queued, but more importantly, we look at the Processor Control Block (PRCB).
Plaintext
kd> !prcb
...
DpcRoutine: fffff801`4b331010 MyStorageDriver!RequestTimeoutHandler
Step 3: Analyzing the Code
We examine MyStorageDriver!RequestTimeoutHandler.
C
while (HardwareStatus != READY) {
// Busy waiting for a register bit to flip
// No timeout, no yielding
}
The Flaw: The driver is “spinning” in a while loop waiting for hardware that has hung. Because this is a DPC, no other thread can preempt it on this core. The Watchdog timer expires because the CPU hasn’t returned to a lower IRQL in several milliseconds.
3. Debugging Tools for Timeouts
If the stack trace is unclear, use these commands:
!stacks 2: Look for threads stuck inDISPATCH_LEVEL.!timer: See if any system timers were supposed to fire but were blocked by the runaway DPC.!runaway: Shows which threads have consumed the most CPU time.
4. How to Fix It (Blog Advice)
- Use Hardware Timeouts: Never write a
whileloop without a maximum retry count or a timestamp check. - Offload to Worker Threads: If you have massive data processing to do, don’t do it in the DPC. Queue a System Worker Thread (which runs at $IRQL = 0$) so the scheduler can still breathe.
- Use KeStallExecutionProcessor Sparingly: Only use stalls for microseconds, never milliseconds.
Summary Table: Timeout & Logic Bug Checks
| Code | Name | Typical Cause |
| 0x133 | DPC_WATCHDOG_VIOLATION | A DPC ran too long or the system stayed at DISPATCH_LEVEL too long. |
| 0x101 | CLOCK_WATCHDOG_TIMEOUT | A secondary processor is not responding to interrupts (often hardware/voltage). |
| 0x9F | DRIVER_POWER_STATE_FAILURE | A driver is taking too long to respond to a Power IRP (sleep/hibernate). |
| 0x139 | KERNEL_SECURITY_CHECK_FAILURE | A stack buffer overrun was detected (modern replacement for some 0x19 cases). |
In the next and final article of this introductory series, we will discuss Resource Deadlocks (0x15F and 0x9F)—where two threads are waiting for each other, and nobody is moving.
