Deadlocks

With the greater degree of multi-tasking available in Windows 95, the opportunity for deadlocking the system grows enormously. Moreover, some operations, while not deadlocking the system, effectively shut off multi-tasking until the operation completes. The section on events will discuss various deadlock issues related to events. Here are some other issues:

Remember that there are two components in the system which together control whether a thread may run. VxDs interact with the ring 0 scheduler and time slicer, whose rules for choosing which thread may run can be oversimplified to 'run the highest priority thread not blocked on a ring 0 synchronization object'. Meanwhile, there is also a ring 3 scheduler implemented in Kernel32 which has its own rules for which thread may run, based on things applications do, such as WaitForSingleObject or GetMessage. In order for a thread to run at ring 3, both schedulers must agree that the thread is runnable.

For example, a common scenario is for a VxD to block thread A at ring 0 and wait until thread B does some work at ring 3. If thread A owns some resource at ring 3 which thread B requires, then the system grinds to a halt because thread B cannot run until thread A releases the resource, but thread A is waiting for thread B to do something.

Another common scenario is for a VxD to attempt to acquire a resource at event or timeout time which the current thread already owns. This results in even shorter deadlock chain, where a thread ends up waiting for itself. Examples of this will be given in the chapter on events, but the general rule is not to block inside an event or timeout. Even if you don't deadlock the system, you will almost certainly cause multi-tasking to halt until the thread unblocks.

Another scenario is to call Begin_Critical_Section, followed by some other operation which blocks on a synchronization object. 'Blocking with the critical section' usually deadlocks the system because large numbers of important system operations require the critical section in order to proceed. By holding onto the critical section while waiting for something else, those other important system operations cannot be carried out.

Yet another situation is for thread A to go into a Resume_Exec loop, waiting for some operation to be performed by thread B. Resume_Exec does not block but merely processes events, so if thread B does not have sufficiently high priority, it will never run and thus thread A will wait forever.