utils.cpp
来自「这个是串口驱动程序开发包」· C++ 代码 · 共 592 行 · 第 1/2 页
CPP
592 行
/*++
Abstract:
This module contains code that perform queueing and completion
manipulation on requests.
--*/
#include "precomp.h"
VOID
SerialRundownIrpRefs(
IN PKdIrp CurrentOpIrp,
IN PKdTimer IntervalTimer,
IN PKdTimer TotalTimer
);
VOID KdSerialDevice::KillAllReadsOrWrites(
IN PLIST_ENTRY QueueToClean,
IN PKdIrp CurrentOpIrp
)
/*++
Routine Description:
This function is used to cancel all queued and the current irps
for reads or for writes.
Arguments:
QueueToClean - A pointer to the queue which we're going to clean out.
CurrentOpIrp - Pointer to a pointer to the current irp.
--*/
{
KIRQL cancelIrql;
PDRIVER_CANCEL cancelRoutine;
// We acquire the cancel spin lock. This will prevent the
// irps from moving around.
IoAcquireCancelSpinLock(&cancelIrql);
// Clean the list from back to front.
while (!IsListEmpty(QueueToClean))
{
KdIrp currentLastIrp = CONTAINING_RECORD(
QueueToClean->Blink,
IRP,
Tail.Overlay.ListEntry
);
RemoveEntryList(QueueToClean->Blink);
cancelRoutine = currentLastIrp->CancelRoutine;
currentLastIrp->CancelIrql = cancelIrql;
currentLastIrp->CancelRoutine = NULL;
currentLastIrp->Cancel = TRUE;
cancelRoutine(
m_pDeviceObject,
currentLastIrp
);
IoAcquireCancelSpinLock(&cancelIrql);
}
// The queue is clean. Now go after the current if
// it's there.
if (*CurrentOpIrp)
{
cancelRoutine = (*CurrentOpIrp)->CancelRoutine;
(*CurrentOpIrp)->Cancel = TRUE;
// If the current irp is not in a cancelable state
// then it *will* try to enter one and the above
// assignment will kill it. If it already is in
// a cancelable state then the following will kill it.
if (cancelRoutine)
{
(*CurrentOpIrp)->CancelRoutine = NULL;
(*CurrentOpIrp)->CancelIrql = cancelIrql;
// This irp is already in a cancelable state. We simply
// mark it as canceled and call the cancel routine for it.
cancelRoutine(
m_pDeviceObject,
*CurrentOpIrp
);
}
else
IoReleaseCancelSpinLock(cancelIrql);
}
else
IoReleaseCancelSpinLock(cancelIrql);
}
VOID KdSerialDevice::GetNextIrp(
IN PKdIrp CurrentOpIrp,
IN PLIST_ENTRY QueueToProcess,
OUT PKdIrp NextIrp,
IN BOOLEAN CompleteCurrent
)
/*++
Routine Description:
This function is used to make the head of the particular
queue the current irp. It also completes the what
was the old current irp if desired.
Arguments:
CurrentOpIrp - Pointer to a pointer to the currently active
irp for the particular work list. Note that
this item is not actually part of the list.
QueueToProcess - The list to pull the new item off of.
NextIrp - The next Irp to process. Note that CurrentOpIrp
will be set to this value under protection of the
cancel spin lock. However, if *NextIrp is NULL when
this routine returns, it is not necessaryly true the
what is pointed to by CurrentOpIrp will also be NULL.
The reason for this is that if the queue is empty
when we hold the cancel spin lock, a new irp may come
in immediately after we release the lock.
CompleteCurrent - If TRUE then this routine will complete the
irp pointed to by the pointer argument
CurrentOpIrp.
--*/
{
KIRQL oldIrql;
KdIrp oldIrp;
IoAcquireCancelSpinLock(&oldIrql);
oldIrp = *CurrentOpIrp;
if (oldIrp)
{
if (CompleteCurrent)
ASSERT(!oldIrp->CancelRoutine);
}
// Check to see if there is a new irp to start up.
if (!IsListEmpty(QueueToProcess))
{
PLIST_ENTRY headOfList;
headOfList = RemoveHeadList(QueueToProcess);
*CurrentOpIrp = CONTAINING_RECORD(
headOfList,
IRP,
Tail.Overlay.ListEntry
);
IoSetCancelRoutine(
*CurrentOpIrp,
NULL
);
}
else
*CurrentOpIrp = (PIRP) NULL;
*NextIrp = *CurrentOpIrp;
IoReleaseCancelSpinLock(oldIrql);
if (CompleteCurrent)
{
if (oldIrp)
{
DebugDump(DBG_DIAG6, ("Complete Irp: %x\n",oldIrp) );
oldIrp.Complete(IO_SERIAL_INCREMENT);
}
}
}
VOID KdSerialDevice::TryToCompleteCurrent(
IN KDIRQ_SYNC_CALLBACK SynchRoutine OPTIONAL,
IN KIRQL IrqlForRelease,
IN NTSTATUS StatusToUse,
IN PKdIrp CurrentOpIrp,
IN PLIST_ENTRY QueueToProcess OPTIONAL,
IN PKdTimer IntervalTimer OPTIONAL,
IN PKdTimer TotalTimer OPTIONAL,
IN PSERIAL_START_ROUTINE Starter OPTIONAL,
IN P_GET_NEXT_ROUTINE GetNextIrpRoutine OPTIONAL,
IN LONG RefType
)
/*++
Routine Description:
This routine attempts to kill all of the reasons there are
references on the current read/write. If everything can be killed
it will complete this read/write and try to start another.
NOTE: This routine assumes that it is called with the cancel
spinlock held.
Arguments:
SynchRoutine - A routine that will synchronize with the isr
and attempt to remove the knowledge of the
current irp from the isr. NOTE: This pointer
can be null.
IrqlForRelease - This routine is called with the cancel spinlock held.
This is the irql that was current when the cancel
spinlock was acquired.
StatusToUse - The irp's status field will be set to this value, if
this routine can complete the irp.
--*/
{
// We can decrement the reference to "remove" the fact
// that the caller no longer will be accessing this irp.
SERIAL_CLEAR_REFERENCE(
*CurrentOpIrp,
RefType
);
if (SynchRoutine)
m_KdInterrupt.SynchronizeExecution(SynchRoutine);
// Try to run down all other references to this irp.
SerialRundownIrpRefs(
CurrentOpIrp,
IntervalTimer,
TotalTimer
);
// See if the ref count is zero after trying to kill everybody else.
if (!SERIAL_REFERENCE_COUNT(*CurrentOpIrp))
{
KdIrp newIrp;
// The ref count was zero so we should complete this
// request.
//
// The following call will also cause the current irp to be
// completed.
CurrentOpIrp->Status() = StatusToUse;
if (StatusToUse == STATUS_CANCELLED)
CurrentOpIrp->Information() = 0;
if (GetNextIrpRoutine)
{
IoReleaseCancelSpinLock(IrqlForRelease);
(this->*GetNextIrpRoutine)(
CurrentOpIrp,
QueueToProcess,
&newIrp,
TRUE
);
if (newIrp)
(this->*Starter)();
}
else
{
KdIrp oldIrp = *CurrentOpIrp;
// There was no get next routine. We will simply complete
// the irp. We should make sure that we null out the
// pointer to the pointer to this irp.
*CurrentOpIrp = (PIRP) NULL;
IoReleaseCancelSpinLock(IrqlForRelease);
DebugDump(DBG_DIAG6, ("Complete Irp: %x\n",oldIrp) );
oldIrp.Complete(IO_SERIAL_INCREMENT);
}
}
else
IoReleaseCancelSpinLock(IrqlForRelease);
}
VOID
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?