ID: Q176905
The information in this article applies to:
Deadlock might occur when a Windows 95 application tries to take a level 3 volume lock. The following is a typical scenario:
Process A (32-bit) Process B (16-bit)
_________________________ _________________________
| | | |
| 1. Acquire level 2 lock | | |
| | | |
| | 2. Process A | |
| | preempted | |
| | ---------------> | |
| | | 3. Attempt a file write |
| | | |
| | | -acquire kernel32 |
| | | lock |
| | | |
| | | -IFS manager blocks |
| | | on write (Process A |
| | | owns level 2 lock) |
| | 4. Process A | |
| | rescheduled | |
| | <--------------- | |
| 5. Request for level 3 | | |
| lock blocks on | | |
| request for kernel32 | | |
| lock (owned by | | |
| Process B) | | |
|_________________________| |_________________________|
1. Process A, a 32-bit Windows application, acquires a level 2 volume lock.
2. Process A's running thread is preempted.
3. Process B makes a 16-bit Windows API call requiring write access on the
locked drive. The API acquires the kernel32 lock prior to passing
the request to the IFS manager. The thread is blocked because it is
denied write access until process A releases the level 2 lock.
4. Process A is rescheduled.
5. Process A requests the level 3 volume lock. The level 3 lock first
tries to acquire the kernel32 lock. The thread subsequently blocks,
since the kernel32 lock is already owned by process B.
Both processes are now blocked, each one is waiting on a resource that the
other owns.
The deadlock takes place because the order in which the resources (write access to the disk and the kernel32 lock) are requested differs between the two processes and because the acquisition of these resources is not an atomic transaction. Furthermore, the problem only seems to show up when another process is performing 16-bit file I/O on the locked volume.
There is no viable workaround for 32-bit code. The Windows 95 disk utilities avoid this problem by thunking to 16-bit code, thereby assuring that the acquisition of the level 2 and level 3 volume locks is done atomically.
Process A (32-bit) Process B (16-bit)
_________________________ _________________________
| | | |
| 1. Thunk to 16-bit code | | |
| | | |
| 2. Acquire level 2 lock | | |
| | | |
| 3. Acquire level 3 lock | | |
| (acquires kernel32 | | |
| lock) | | |
| | | |
| 4. Return from thunk | | |
| | | |
| | 5. Process A | |
| | preempted | |
| | ---------------> | |
| | | 6. Write blocks on |
| | | request for kernel32 |
| | | lock |
| | | |
| | 7. Process A | |
| | rescheduled | |
| | <--------------- | |
| | | |
| 8. Release level 3 lock | | |
| (releases kernel32 | | |
| lock) | | |
|_________________________| |_________________________|
There is no deadlock here, since process B is no longer blocked. In
reality, process A may be preempted between steps 2 and 3 above, but since
it will then own the Win16 mutex, no other 16-bit process may be scheduled.
Note that this will have consequences on the code design. To ensure
atomicity, the Win16 mutex must not be released between requests for the
level 2 and level 3 volume locks. Hence, these operations must be performed
from within the context of a single thunk.
Microsoft has confirmed this to be a bug in the Microsoft products listed at the beginning of this article. We are researching this bug and will post new information here in the Microsoft Knowledge Base as it becomes available.
Note that this problem is fixed in the Windows 95 OEM Service Release 2 (OSR2).
Additional query words: disk I/O diskio access kernel base win95
Keywords : kbAPI kbKernBase kbGrpKernBase
Version : WINNT:
Platform : winnt
Hardware : x86
Issue type : kbbug
Last Reviewed: November 20, 1997