Short answer: yes, you are not using the relock correctly. Also, you should always use uniquely paired tag values for acquire/release so that you can catch errors like this under verifier in Vista and later or on a chk build for a prev release
Long answer: remlocks are a little quirky in how they are initialized and destroyed. First, you can only init them at passive which does not allow them to be a generally purpose ref counting with a synchronous deletion object. Second, once a remlock has been ReleleaseAndWait’ed, the only way to reinit is to call InitializeRemLock which has the IRQL restriction. Third and most important to your question, the contract for ReleaseAndWait is that the caller must acquire the remlock before this call is made. This allows for the pnp dispatch routine to always have an acquire rem lock at the top of the function, regardless of pnp minor code.
ReleaseAndWait will release the previous acquire, remove the initial bias on the io count (e.g. subtract one) and if the result is !=0, wait. This is why you see the count go down by 2. To fix your code you should have a remlock acquire before sending the irp and then releasing the remlock in the completion routine. This way the completion routine’s release is paired with the acquire before send, not the acquire for releaseandwait
d
-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@siemens.com
Sent: Friday, May 16, 2008 7:18 AM
To: Windows System Software Devs Interest List
Subject: [ntdev] IoReleaseRemoveLockAndWait() does not wait
Hello,
I try to cancel an asynchronous IRP. Before freeing the IRP after canceling it I
wait for an IoCount reaching zero. I am realizing this mechanism by using the
IoAcquireRemoveLock and Release functions.
My IRP-Cancelation looks like this:
CancelIrp()
{
IoAcquireRemoveLock(&lock, NULL);
IoCancelIrp(irp);
IoReleaseRemoveLockAndWait(&lock);
…
IoFreeIrp(irp);
}
The IRP Completion does this:
OnCompletion()
{
…
IoReleaseRemoveLock(&lock);
return STATUS_MORE_PROCESSING_REQUIRED;
}
I would consider that the following sequence would take place if the last
outstanding IRP gets canceled:
- IoAcquireRemoveLock() –> lock.Common.IoCount 0x1 -> 0x2
- IoCancelIrp() succeeds
- IoReleaseRemoveLockAndWait() –> IoCount 0x2 -> 0x1
- IoReleaseRemoveLockAndWait() waits for IoCount becomming 0x0 …
- OnCompletion()
- IoReleaseRemoveLock() –> IoCount 0x1 -> 0x0
- IoReleaseRemoveLockAndWait() returns from waiting and Lock gets removed.
- Irp can be securely be removed.
But instead of this the following happens:
- IoAcquireRemoveLock() –> lock.Common.IoCount 0x1 -> 0x2
- IoCancelIrp() succeeds
- IoReleaseRemoveLockAndWait() –> IoCount 0x2 -> 0x0 !!!
- IoReleaseRemoveLockAndWait() returns and disables the lock.
Now I get a BugCheck for one of the following
* The lower IoCompletion bugchecks because the irp was freed to early.
* OnCompletion() bugchecks with a BAD_POOL_CALLER because the lock was removed
I hope anyone has a solution for this. I consider that I am using the
IoAcquire/ReleaseRemoveLock functions wrong.
Greetings
Emanuel Eick
NTDEV is sponsored by OSR
For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars
To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer