📄 read.c
字号:
while (!IsListEmpty(&irpsToCompleteList)){
listEntry = RemoveHeadList(&irpsToCompleteList);
ASSERT(listEntry);
irp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
DBGVERBOSE(("SatisfyPendingReads: completing irp with %xh bytes.", irp->IoStatus.Information));
/*
* Free the MDL we created for the UserBuffer
*/
ASSERT(irp->MdlAddress);
MmUnlockPages(irp->MdlAddress);
FREEPOOL(irp->MdlAddress);
irp->MdlAddress = NULL;
IoCompleteRequest(irp, IO_NO_INCREMENT);
}
while (!IsListEmpty(&readPacketsToFree)){
listEntry = RemoveHeadList(&readPacketsToFree);
ASSERT(listEntry);
readPacket = CONTAINING_RECORD(listEntry, READPACKET, listEntry);
FreeReadPacket(readPacket);
}
}
/*
* IssueReadForClient
*
* Must be called with exclusive access on the input endpoint held.
*/
VOID IssueReadForClient(POSPDOEXT *pdoExt)
{
PUCHAR readBuf;
ULONG readLen;
DBGVERBOSE(("IssueReadForClient"));
/*
* We always read the full pipe size.
*
* BUGBUG - pipe info needs to be moved to pdoExt.
*/
readLen = pdoExt->inputEndpointInfo.pipeLen;
readBuf = ALLOCPOOL(NonPagedPool, readLen);
if (readBuf){
READPACKET *readPacket;
RtlZeroMemory(readBuf, readLen);
readPacket = AllocReadPacket(readBuf, readLen, pdoExt);
if (readPacket){
ReadPipe(pdoExt->parentFdoExt, pdoExt->inputEndpointInfo.pipeHandle, readPacket, FALSE);
}
else {
FREEPOOL(readBuf);
FlushBuffers(pdoExt);
}
}
else {
ASSERT(readBuf);
FlushBuffers(pdoExt);
}
}
VOID WorkItemCallback_Read(PVOID context)
{
POSPDOEXT *pdoExt = context;
KIRQL oldIrql;
BOOLEAN issueReadNow = FALSE;
DBGVERBOSE(("WorkItemCallback_Read"));
KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
if (IsListEmpty(&pdoExt->pendingReadIrpsList)){
DBGERR(("WorkItemCallback_Read: list is empty ?!"));
}
else {
if (pdoExt->inputEndpointInfo.endpointIsBusy){
DBGWARN(("WorkItemCallback_Read: endpoint is busy"));
}
else {
pdoExt->inputEndpointInfo.endpointIsBusy = TRUE;
issueReadNow = TRUE;
}
}
KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
if (issueReadNow){
IssueReadForClient(pdoExt);
}
}
NTSTATUS EnqueueReadIrp(POSPDOEXT *pdoExt, PIRP irp, BOOLEAN enqueueAtFront, BOOLEAN lockHeld)
{
PDRIVER_CANCEL oldCancelRoutine;
NTSTATUS status = STATUS_PENDING;
KIRQL oldIrql;
if (!lockHeld) KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
/*
* Enqueue the IRP
*/
if (enqueueAtFront){
InsertHeadList(&pdoExt->pendingReadIrpsList, &irp->Tail.Overlay.ListEntry);
}
else {
InsertTailList(&pdoExt->pendingReadIrpsList, &irp->Tail.Overlay.ListEntry);
}
/*
* Apply the IoMarkIrpPending macro to indicate that the
* irp may complete on a different thread.
* The kernel will see this flag set when we complete the IRP and get the IRP
* back on the right thread if there was a synchronous client.
*/
IoMarkIrpPending(irp);
/*
* Must set the cancel routine before checking the cancel flag.
*/
oldCancelRoutine = IoSetCancelRoutine(irp, ReadCancelRoutine);
ASSERT(!oldCancelRoutine);
if (irp->Cancel){
/*
* This IRP was cancelled.
* We need to coordinate with the cancel routine to complete this irp.
*/
oldCancelRoutine = IoSetCancelRoutine(irp, NULL);
if (oldCancelRoutine){
/*
* Cancel routine was not called, so dequeue the IRP and return
* error so the dispatch routine completes the IRP.
*/
ASSERT(oldCancelRoutine == ReadCancelRoutine);
RemoveEntryList(&irp->Tail.Overlay.ListEntry);
status = STATUS_CANCELLED;
}
else {
/*
* Cancel routine was called and it will complete the IRP
* as soon as we drop the spinlock. So don't touch this IRP.
* Return PENDING so dispatch routine won't complete the IRP.
*/
}
}
if (!lockHeld) KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
return status;
}
PIRP DequeueReadIrp(POSPDOEXT *pdoExt, BOOLEAN lockHeld)
{
PIRP nextIrp = NULL;
KIRQL oldIrql;
if (!lockHeld) KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
while (!nextIrp && !IsListEmpty(&pdoExt->pendingReadIrpsList)){
PDRIVER_CANCEL oldCancelRoutine;
PLIST_ENTRY listEntry = RemoveHeadList(&pdoExt->pendingReadIrpsList);
nextIrp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
oldCancelRoutine = IoSetCancelRoutine(nextIrp, NULL);
/*
* IoCancelIrp() could have just been called on this IRP.
* What we're interested in is not whether IoCancelIrp() was called (nextIrp->Cancel flag set),
* but whether IoCancelIrp() called (or is about to call) our cancel routine.
* To check that, check the result of the test-and-set macro IoSetCancelRoutine.
*/
if (oldCancelRoutine){
/*
* Cancel routine not called for this IRP. Return this IRP.
*/
ASSERT(oldCancelRoutine == ReadCancelRoutine);
}
else {
/*
* This IRP was just cancelled and the cancel routine was (or will be) called.
* The cancel routine will complete this IRP as soon as we drop the spinlock.
* So don't do anything with the IRP.
* Also, the cancel routine will try to dequeue the IRP,
* so make the IRP's listEntry point to itself.
*/
ASSERT(nextIrp->Cancel);
InitializeListHead(&nextIrp->Tail.Overlay.ListEntry);
nextIrp = NULL;
}
}
if (!lockHeld) KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
return nextIrp;
}
VOID ReadCancelRoutine(PDEVICE_OBJECT devObj, PIRP irp)
{
DEVEXT *devExt;
POSPDOEXT *pdoExt;
KIRQL oldIrql;
DBGWARN(("ReadCancelRoutine: devObj=%ph, irp=%ph.", devObj, irp));
devExt = devObj->DeviceExtension;
ASSERT(devExt->signature == DEVICE_EXTENSION_SIGNATURE);
ASSERT(devExt->isPdo);
pdoExt = &devExt->pdoExt;
IoReleaseCancelSpinLock(irp->CancelIrql);
KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
RemoveEntryList(&irp->Tail.Overlay.ListEntry);
KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
irp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(irp, IO_NO_INCREMENT);
}
READPACKET *AllocReadPacket(PVOID data, ULONG dataLen, PVOID context)
{
READPACKET *readPacket;
readPacket = ALLOCPOOL(NonPagedPool, sizeof(READPACKET));
if (readPacket){
readPacket->signature = READPACKET_SIG;
readPacket->data = data;
readPacket->length = dataLen;
readPacket->offset = 0;
readPacket->context = context;
readPacket->urb = BAD_POINTER;
readPacket->listEntry.Flink = readPacket->listEntry.Blink = BAD_POINTER;
}
else {
ASSERT(readPacket);
}
return readPacket;
}
VOID FreeReadPacket(READPACKET *readPacket)
{
DBGVERBOSE(("Freeing readPacket..."));
ASSERT(readPacket->signature == READPACKET_SIG);
FREEPOOL(readPacket->data);
FREEPOOL(readPacket);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -