DriverA:Enter A HelloDDKRead
DriverA:Leave A HelloDDKRead
DriverA:complete the Driver A IRP_MJ_READ irp!ontimedpc调用了iocompleterequest()
此时已经返回到DriverB,才能继续调用ZwClose(hDevice);下面两行就是证据
DriverA:Enter A HelloDDKClose
DriverA:Leave A HelloDDKClose
DriverB:Leave B HelloDDKRead
DriverB:Enter B HelloDDKClose
DriverB:Leave B HelloDDKClose
watchdog!WdUpdateRecoveryState: Recovery enabled.
DriverB->ZwReadfile->NtReadFile()->IopPerformSynchronousRequest()
......
[COLOR="Red"]//在此情景中,DeviceObject对应与DriverA的设备对象.IoCallDriver即是调用DriverA的Read派遣函数。
由上面的代码可以看出,DriverA的read派遣函数没做什么操作,直接返回STATUS_PENDING了[/COLOR]
Status = IoCallDriver(DeviceObject, Irp);
...
if (SynchIo)
{
/* Make sure the IRP was completed, but returned pending */
if (Status == STATUS_PENDING)
[COLOR="red"]{/*于是,NtReadFile就在这里一直等着,直到事件被设置。
此事件是DriverA的ontimedpc函数中的IoCompleteRequest来设置的,转到下面的IoCompleteRequest源代码[/COLOR]
/* Wait for the IRP */
Status = KeWaitForSingleObject(&FileObject->Event,
Executive,
PreviousMode,
(FileObject->Flags &
FO_ALERTABLE_IO),
NULL);
................
}
DriverA->OnTimeDpc->IoCompleteRequest->IofCompleteRequest
.......
do
{
/* Set Pending Returned */
[COLOR="red"] //只有在DriverA中调用IoMarkIrpPending,才能在此处使Irp->PendingRetured = 1,
从而才能调用后面蓝色部分,使DriverB等待的事件得以设置。这样就能从DriverB中返回了。
正因为如此,如果不调用IoMarkIrpPending,DriverB就只有一直等待了,终于搞明白了[/COLOR]
Irp->PendingReturned = StackPtr->Control & SL_PENDING_RETURNED;
........
/*
* Either we didn't return from the request, or we did return but this
* request was synchronous.
*/
if (([COLOR="blue"]Irp->PendingReturned) [/COLOR]&& (FileObject))
{
/* So we did return with a synch operation, was it the IRP? */
if (Irp->Flags & IRP_SYNCHRONOUS_API)
{
/* Yes, this IRP was synchronous, so return the I/O Status */
*Irp->UserIosb = Irp->IoStatus;
/* Now check if the user gave an event */
if (Irp->UserEvent)
{
/* Signal it */
[COLOR="blue"] KeSetEvent(Irp->UserEvent, 0, FALSE);[/COLOR] }
else
{
/* No event was given, so signal the FO instead */
KeSetEvent(&FileObject->Event, 0, FALSE);
}
}
else
{
/*
* It's not the IRP that was synchronous, it was the FO
* that was opened this way. Signal its event.
*/
FileObject->FinalStatus = Irp->IoStatus.Status;
KeSetEvent(&FileObject->Event, 0, FALSE);
}
}