驱动开发之五 --- TDI之十 【译文】
转自 http://hi.baidu.com/combojiang/blog/item/c5920d2aab63bc28d42af1c8.html
/**/
/**********************************************************************
*
* HandleIrp_RemoveNextIrp
*
* This function removes the next valid IRP.
*
**********************************************************************/
PIRP HandleIrp_RemoveNextIrp(PIRPLISTHEAD pIrpListHead)
{
PIRP pIrp = NULL;
KIRQL kOldIrql;
PDRIVER_CANCEL pCancelRoutine;
PIRPLIST pIrpListCurrent;
KeAcquireSpinLock(&pIrpListHead->kspIrpListLock, &kOldIrql);
pIrpListCurrent = pIrpListHead->pListFront;
while(pIrpListCurrent && pIrp == NULL)
{
/**//*
* To remove an IRP from the Queue we first want to
* reset the cancel routine.
*/
pCancelRoutine = IoSetCancelRoutine(pIrpListCurrent->pIrp, NULL);
/**//*
* The next phase is to determine if this IRP has been canceled
*/
if(pIrpListCurrent->pIrp->Cancel)
{
/**//*
* We have been canceled so we need to determine if our
* cancel routine has already been called. pCancelRoutine
* will be NULL if our cancel routine has been called.
* If will not be NULL if our cancel routine has not been
* called. However, we don't care in either case and we
* will simply complete the IRP here since we have to implement at
* least that case anyway.
*
* Remove the IRP from the list.
*/
pIrpListHead->pListFront = pIrpListCurrent->pNextIrp;
if(pIrpListHead->pListFront == NULL)
{
pIrpListHead->pListBack = NULL;
}
KeReleaseSpinLock(&pIrpListHead->kspIrpListLock, kOldIrql);
pIrpListCurrent->pfnCleanUpIrp(pIrpListCurrent->pIrp,
pIrpListCurrent->pContext);
DbgPrint("HandleIrp_RemoveNextIrp Complete Free Memory =
0x%0x \r\n", pIrpListCurrent);
KMem_FreeNonPagedMemory(pIrpListCurrent);
pIrpListCurrent = NULL;
KeAcquireSpinLock(&pIrpListHead->kspIrpListLock,
&kOldIrql);
pIrpListCurrent = pIrpListHead->pListFront;
}
else
{
pIrpListHead->pListFront = pIrpListCurrent->pNextIrp;
if(pIrpListHead->pListFront == NULL)
{
pIrpListHead->pListBack = NULL;
}
pIrp = pIrpListCurrent->pIrp;
KeReleaseSpinLock(&pIrpListHead->kspIrpListLock, kOldIrql);
DbgPrint("HandleIrp_RemoveNextIrp Complete Free Memory = 0x%0x \r\n",
pIrpListCurrent);
KMem_FreeNonPagedMemory(pIrpListCurrent);
pIrpListCurrent = NULL;
KeAcquireSpinLock(&pIrpListHead->kspIrpListLock,
&kOldIrql);
}
}
KeReleaseSpinLock(&pIrpListHead->kspIrpListLock, kOldIrql);
return pIrp;
}
/**/ /**********************************************************************
*
* HandleIrp_PerformCancel
*
* This function removes the specified IRP from the list.
*
**********************************************************************/
NTSTATUS HandleIrp_PerformCancel(PIRPLISTHEAD pIrpListHead, PIRP pIrp)
{
NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;
KIRQL kOldIrql;
PIRPLIST pIrpListCurrent, pIrpListPrevious;
KeAcquireSpinLock(&pIrpListHead->kspIrpListLock,
&kOldIrql);
pIrpListPrevious = NULL;
pIrpListCurrent = pIrpListHead->pListFront;
while(pIrpListCurrent && NtStatus == STATUS_UNSUCCESSFUL)
{
if(pIrpListCurrent->pIrp == pIrp)
{
if(pIrpListPrevious)
{
pIrpListPrevious->pNextIrp = pIrpListCurrent->pNextIrp;
}
if(pIrpListHead->pListFront == pIrpListCurrent)
{
pIrpListHead->pListFront = pIrpListCurrent->pNextIrp;
}
if(pIrpListHead->pListBack == pIrpListCurrent)
{
pIrpListHead->pListBack = pIrpListPrevious;
}
KeReleaseSpinLock(&pIrpListHead->kspIrpListLock, kOldIrql);
NtStatus = STATUS_SUCCESS;
/**//*
* We are going to allow the clean up function to complete the IRP.
*/
pIrpListCurrent->pfnCleanUpIrp(pIrpListCurrent->pIrp,
pIrpListCurrent->pContext);
DbgPrint("HandleIrp_PerformCancel Complete Free Memory = 0x%0x \r\n",
pIrpListCurrent);
KMem_FreeNonPagedMemory(pIrpListCurrent);
pIrpListCurrent = NULL;
KeAcquireSpinLock(&pIrpListHead->kspIrpListLock,
&kOldIrql);
}
else
{
pIrpListPrevious = pIrpListCurrent;
pIrpListCurrent = pIrpListCurrent->pNextIrp;
}
}
KeReleaseSpinLock(&pIrpListHead->kspIrpListLock, kOldIrql);
return NtStatus;
}
/**/ /**********************************************************************
*
* TdiExample_CancelRoutine
*
* This function is called if the IRP is ever canceled
*
* CancelIo() from user mode, IoCancelIrp() from the Kernel
*
**********************************************************************/
VOID TdiExample_CancelRoutine(PDEVICE_OBJECT DeviceObject, PIRP pIrp)
{
PIRPLISTHEAD pIrpListHead = NULL;
/**//*
* We must release the cancel spin lock
*/
IoReleaseCancelSpinLock(pIrp->CancelIrql);
DbgPrint("TdiExample_CancelRoutine Called IRP = 0x%0x \r\n", pIrp);
/**//*
* We stored the IRPLISTHEAD context in our DriverContext on the IRP
* before adding it to the queue so it should not be NULL here.
*/
pIrpListHead = (PIRPLISTHEAD)pIrp->Tail.Overlay.DriverContext[0];
pIrp->Tail.Overlay.DriverContext[0] = NULL;
/**//*
* We can then just throw the IRP to the PerformCancel
* routine since it will find it in the queue, remove it and
* then call our clean up routine. Our clean up routine
* will then complete the IRP. If this does not occur then
* our completion of the IRP will occur in another context
* since it is not in the list.
*/
HandleIrp_PerformCancel(pIrpListHead, pIrp);
}
/**/ /**********************************************************************
*
* TdiExample_IrpCleanUp
*
* This function is called to clean up the IRP if it is ever
* canceled after we have given it to the queueing routines.
*
**********************************************************************/
VOID TdiExample_IrpCleanUp(PIRP pIrp, PVOID pContext)
{
pIrp->IoStatus.Status = STATUS_CANCELLED;
pIrp->IoStatus.Information = 0;
pIrp->Tail.Overlay.DriverContext[0] = NULL;
DbgPrint("TdiExample_IrpCleanUp Called IRP = 0x%0x \r\n", pIrp);
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
}
*
* HandleIrp_RemoveNextIrp
*
* This function removes the next valid IRP.
*
**********************************************************************/
PIRP HandleIrp_RemoveNextIrp(PIRPLISTHEAD pIrpListHead)
{
PIRP pIrp = NULL;
KIRQL kOldIrql;
PDRIVER_CANCEL pCancelRoutine;
PIRPLIST pIrpListCurrent;
KeAcquireSpinLock(&pIrpListHead->kspIrpListLock, &kOldIrql);
pIrpListCurrent = pIrpListHead->pListFront;
while(pIrpListCurrent && pIrp == NULL)
{
/**//*
* To remove an IRP from the Queue we first want to
* reset the cancel routine.
*/
pCancelRoutine = IoSetCancelRoutine(pIrpListCurrent->pIrp, NULL);
/**//*
* The next phase is to determine if this IRP has been canceled
*/
if(pIrpListCurrent->pIrp->Cancel)
{
/**//*
* We have been canceled so we need to determine if our
* cancel routine has already been called. pCancelRoutine
* will be NULL if our cancel routine has been called.
* If will not be NULL if our cancel routine has not been
* called. However, we don't care in either case and we
* will simply complete the IRP here since we have to implement at
* least that case anyway.
*
* Remove the IRP from the list.
*/
pIrpListHead->pListFront = pIrpListCurrent->pNextIrp;
if(pIrpListHead->pListFront == NULL)
{
pIrpListHead->pListBack = NULL;
}
KeReleaseSpinLock(&pIrpListHead->kspIrpListLock, kOldIrql);
pIrpListCurrent->pfnCleanUpIrp(pIrpListCurrent->pIrp,
pIrpListCurrent->pContext);
DbgPrint("HandleIrp_RemoveNextIrp Complete Free Memory =
0x%0x \r\n", pIrpListCurrent);
KMem_FreeNonPagedMemory(pIrpListCurrent);
pIrpListCurrent = NULL;
KeAcquireSpinLock(&pIrpListHead->kspIrpListLock,
&kOldIrql);
pIrpListCurrent = pIrpListHead->pListFront;
}
else
{
pIrpListHead->pListFront = pIrpListCurrent->pNextIrp;
if(pIrpListHead->pListFront == NULL)
{
pIrpListHead->pListBack = NULL;
}
pIrp = pIrpListCurrent->pIrp;
KeReleaseSpinLock(&pIrpListHead->kspIrpListLock, kOldIrql);
DbgPrint("HandleIrp_RemoveNextIrp Complete Free Memory = 0x%0x \r\n",
pIrpListCurrent);
KMem_FreeNonPagedMemory(pIrpListCurrent);
pIrpListCurrent = NULL;
KeAcquireSpinLock(&pIrpListHead->kspIrpListLock,
&kOldIrql);
}
}
KeReleaseSpinLock(&pIrpListHead->kspIrpListLock, kOldIrql);
return pIrp;
}
/**/ /**********************************************************************
*
* HandleIrp_PerformCancel
*
* This function removes the specified IRP from the list.
*
**********************************************************************/
NTSTATUS HandleIrp_PerformCancel(PIRPLISTHEAD pIrpListHead, PIRP pIrp)
{
NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;
KIRQL kOldIrql;
PIRPLIST pIrpListCurrent, pIrpListPrevious;
KeAcquireSpinLock(&pIrpListHead->kspIrpListLock,
&kOldIrql);
pIrpListPrevious = NULL;
pIrpListCurrent = pIrpListHead->pListFront;
while(pIrpListCurrent && NtStatus == STATUS_UNSUCCESSFUL)
{
if(pIrpListCurrent->pIrp == pIrp)
{
if(pIrpListPrevious)
{
pIrpListPrevious->pNextIrp = pIrpListCurrent->pNextIrp;
}
if(pIrpListHead->pListFront == pIrpListCurrent)
{
pIrpListHead->pListFront = pIrpListCurrent->pNextIrp;
}
if(pIrpListHead->pListBack == pIrpListCurrent)
{
pIrpListHead->pListBack = pIrpListPrevious;
}
KeReleaseSpinLock(&pIrpListHead->kspIrpListLock, kOldIrql);
NtStatus = STATUS_SUCCESS;
/**//*
* We are going to allow the clean up function to complete the IRP.
*/
pIrpListCurrent->pfnCleanUpIrp(pIrpListCurrent->pIrp,
pIrpListCurrent->pContext);
DbgPrint("HandleIrp_PerformCancel Complete Free Memory = 0x%0x \r\n",
pIrpListCurrent);
KMem_FreeNonPagedMemory(pIrpListCurrent);
pIrpListCurrent = NULL;
KeAcquireSpinLock(&pIrpListHead->kspIrpListLock,
&kOldIrql);
}
else
{
pIrpListPrevious = pIrpListCurrent;
pIrpListCurrent = pIrpListCurrent->pNextIrp;
}
}
KeReleaseSpinLock(&pIrpListHead->kspIrpListLock, kOldIrql);
return NtStatus;
}
/**/ /**********************************************************************
*
* TdiExample_CancelRoutine
*
* This function is called if the IRP is ever canceled
*
* CancelIo() from user mode, IoCancelIrp() from the Kernel
*
**********************************************************************/
VOID TdiExample_CancelRoutine(PDEVICE_OBJECT DeviceObject, PIRP pIrp)
{
PIRPLISTHEAD pIrpListHead = NULL;
/**//*
* We must release the cancel spin lock
*/
IoReleaseCancelSpinLock(pIrp->CancelIrql);
DbgPrint("TdiExample_CancelRoutine Called IRP = 0x%0x \r\n", pIrp);
/**//*
* We stored the IRPLISTHEAD context in our DriverContext on the IRP
* before adding it to the queue so it should not be NULL here.
*/
pIrpListHead = (PIRPLISTHEAD)pIrp->Tail.Overlay.DriverContext[0];
pIrp->Tail.Overlay.DriverContext[0] = NULL;
/**//*
* We can then just throw the IRP to the PerformCancel
* routine since it will find it in the queue, remove it and
* then call our clean up routine. Our clean up routine
* will then complete the IRP. If this does not occur then
* our completion of the IRP will occur in another context
* since it is not in the list.
*/
HandleIrp_PerformCancel(pIrpListHead, pIrp);
}
/**/ /**********************************************************************
*
* TdiExample_IrpCleanUp
*
* This function is called to clean up the IRP if it is ever
* canceled after we have given it to the queueing routines.
*
**********************************************************************/
VOID TdiExample_IrpCleanUp(PIRP pIrp, PVOID pContext)
{
pIrp->IoStatus.Status = STATUS_CANCELLED;
pIrp->IoStatus.Information = 0;
pIrp->Tail.Overlay.DriverContext[0] = NULL;
DbgPrint("TdiExample_IrpCleanUp Called IRP = 0x%0x \r\n", pIrp);
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
}