> * You are using fast mutexes. Using a fast mutex around a Zw* API call is
prohibited because it will raise IRQL above PASSIVE_LEVEL and this will in
turn block the delivery of APCs which are essential to correct I/O
completion. The DDK clearly documents that Zw I/O calls may only be used
at
PASSIVE_LEVEL (and for good reason.)
It is a good idea to NEVER call any complex stuff like ZwCreateFile while
holding a lock. Let’s imagine you need to call a ComplexFunction while
initializing some structure. Then:
- add the “completely initialized” flag and KEVENT in the structure layout.
- write the code as the following:
- grab the lock
- find the structure in the list
- if not found - allocate it, put it on the list, set the flag to
“not completely
initialized” and the event to non-signaled, set the local
variables
AddedByMe to TRUE and MustWait to TRUE - if found and the flag is set to “not completely initialized” - set
AddedByMe to FALSE and MustWait to TRUE - if found and the flag is set to “completely initialized” - set
AddedByMe to FALSE and MustWait to FALSE - release the lock
- if AddedByMe is TRUE - do the ComplexFunction stuff, then
- grab the lock
- set the flag to “completely initialized” and signal the event
- release the lock
- else if MustWait is TRUE - wait on the event
- return the structure pointer
This logic is free from races and does the ComplexFunction call without any
locks held.
NT uses this to call IoPageRead in the pagefault path - no MM locks are held
during the call, and collided faults are handled in race-free way.
Max