|
|
#include "internal.h"
#pragma alloc_text(PAGE,InitializePacketQueue)
VOID InitializePacketQueue( PPACKET_QUEUE PacketQueue, PVOID Context, PACKET_STARTER StarterRoutine )
{
RtlZeroMemory(PacketQueue,sizeof(*PacketQueue));
KeInitializeSpinLock(&PacketQueue->Lock);
PacketQueue->Context=Context;
PacketQueue->Starter=StarterRoutine;
PacketQueue->Active=TRUE;
KeInitializeEvent(&PacketQueue->InactiveEvent,NotificationEvent,FALSE);
InitializeListHead(&PacketQueue->ListHead);
return;
}
VOID IrpQueueCancelRoutine( PDEVICE_OBJECT DeviceObject, PIRP Irp )
{ PPACKET_QUEUE PacketQueue; KIRQL OldIrql;
IoReleaseCancelSpinLock(Irp->CancelIrql);
PacketQueue=Irp->Tail.Overlay.DriverContext[0];
KeAcquireSpinLock(&PacketQueue->Lock,&OldIrql);
if (Irp->Tail.Overlay.ListEntry.Flink == NULL) { //
// the irp has been removed from the queue
//
} else { //
// the irp is still in the queue, remove it
//
RemoveEntryList( &Irp->Tail.Overlay.ListEntry ); }
KeReleaseSpinLock(&PacketQueue->Lock,OldIrql);
Irp->IoStatus.Status=STATUS_CANCELLED; Irp->IoStatus.Information=0;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
return; }
PIRP GetUseableIrp( PLIST_ENTRY List )
{ PIRP Packet=NULL;
while ( (Packet == NULL) && !IsListEmpty(List)) { //
// there is a packet queued
//
PLIST_ENTRY ListEntry;
ListEntry=RemoveTailList(List);
Packet=CONTAINING_RECORD(ListEntry,IRP,Tail.Overlay.ListEntry);
if (IoSetCancelRoutine(Packet,NULL) == NULL) { //
// The cancel rountine has run and is waiting on the queue spinlock,
// set the flink to null so the cancel routine knows not to try
// take the irp off the list
//
Packet->Tail.Overlay.ListEntry.Flink=NULL; Packet=NULL;
//
// try to get another one
//
} }
return Packet;
}
VOID QueuePacket( PPACKET_QUEUE PacketQueue, PIRP Packet, BOOLEAN InsertAtFront )
{
NTSTATUS Status; KIRQL OldIrql; KIRQL CancelIrql; BOOLEAN Canceled=FALSE;
KeAcquireSpinLock(&PacketQueue->Lock,&OldIrql);
if ((PacketQueue->CurrentPacket == NULL) && PacketQueue->Active && (IsListEmpty(&PacketQueue->ListHead))) { //
// not currently handling a packet and the queue is active and there are not other packets
// queued, so handle it now
//
PacketQueue->CurrentPacket=Packet;
KeReleaseSpinLock(&PacketQueue->Lock,OldIrql);
(*PacketQueue->Starter)( PacketQueue->Context, Packet );
return;
}
Packet->Tail.Overlay.DriverContext[0]=PacketQueue;
IoAcquireCancelSpinLock(&CancelIrql);
if (Packet->Cancel) { //
// the irp has already been canceled
//
Canceled=TRUE;
} else {
IoSetCancelRoutine( Packet, IrpQueueCancelRoutine ); }
IoReleaseCancelSpinLock(CancelIrql);
//
// need to queue the packet
//
if (!Canceled) {
if (InsertAtFront) { //
// this one is high priorty for some reason, put it at the front
//
InsertTailList(&PacketQueue->ListHead,&Packet->Tail.Overlay.ListEntry);
} else {
InsertHeadList(&PacketQueue->ListHead,&Packet->Tail.Overlay.ListEntry); } }
KeReleaseSpinLock(&PacketQueue->Lock,OldIrql);
if (Canceled) { //
// complete the canceled irp now
//
Packet->IoStatus.Status=STATUS_CANCELLED; Packet->IoStatus.Information=0;
IoCompleteRequest(Packet,IO_NO_INCREMENT); }
return;
}
VOID StartNextPacket( PPACKET_QUEUE PacketQueue )
{ KIRQL OldIrql;
KeAcquireSpinLock(&PacketQueue->Lock,&OldIrql);
ASSERT(PacketQueue->CurrentPacket != NULL);
//
// done with this one
//
PacketQueue->CurrentPacket=NULL;
if (!PacketQueue->InStartNext) { //
// not already in this function
//
PacketQueue->InStartNext=TRUE;
while ((PacketQueue->CurrentPacket == NULL) && PacketQueue->Active ) { //
// there isn't a current packet and the queue is active
//
PIRP Packet;
Packet=GetUseableIrp(&PacketQueue->ListHead);
if (Packet != NULL) { //
// we got an irp to use
//
// now the current one
//
PacketQueue->CurrentPacket=Packet;
KeReleaseSpinLock(&PacketQueue->Lock,OldIrql);
//
// start the processing
//
(*PacketQueue->Starter)( PacketQueue->Context, Packet );
KeAcquireSpinLock(&PacketQueue->Lock,&OldIrql);
} else { //
// queue is empty, break out of loop
//
break;
}
}
if (!PacketQueue->Active && (PacketQueue->CurrentPacket == NULL)) { //
// the queue has been paused and we don't have a current packet, signal the event
//
KeSetEvent( &PacketQueue->InactiveEvent, IO_NO_INCREMENT, FALSE ); }
PacketQueue->InStartNext=FALSE; }
KeReleaseSpinLock(&PacketQueue->Lock,OldIrql);
return;
}
VOID PausePacketProcessing( PPACKET_QUEUE PacketQueue, BOOLEAN WaitForInactive )
{ KIRQL OldIrql; BOOLEAN CurrentlyActive=FALSE;
KeAcquireSpinLock(&PacketQueue->Lock,&OldIrql);
PacketQueue->Active=FALSE;
if (PacketQueue->CurrentPacket != NULL) { //
// there is a packet currently being processed
//
CurrentlyActive=TRUE;
KeClearEvent(&PacketQueue->InactiveEvent);
}
KeReleaseSpinLock(&PacketQueue->Lock,OldIrql);
if (WaitForInactive && CurrentlyActive) { //
// the caller wants use to wait for the queue to inactive, and it was active when
// theis was called
//
KeWaitForSingleObject( &PacketQueue->InactiveEvent, Executive, KernelMode, FALSE, NULL );
}
return;
}
VOID ActivatePacketProcessing( PPACKET_QUEUE PacketQueue )
{
KIRQL OldIrql;
KeAcquireSpinLock(&PacketQueue->Lock,&OldIrql);
PacketQueue->Active=TRUE;
if ((PacketQueue->CurrentPacket == NULL)) { //
// No packet is currently being used
//
PIRP Packet;
Packet=GetUseableIrp(&PacketQueue->ListHead);
if (Packet != NULL) { //
// we got an irp to use
//
// now the current one
//
PacketQueue->CurrentPacket=Packet;
KeReleaseSpinLock(&PacketQueue->Lock,OldIrql);
//
// start the processing
//
(*PacketQueue->Starter)( PacketQueue->Context, Packet );
KeAcquireSpinLock(&PacketQueue->Lock,&OldIrql);
}
}
KeReleaseSpinLock(&PacketQueue->Lock,OldIrql);
return;
}
VOID FlushQueuedPackets( PPACKET_QUEUE PacketQueue, UCHAR MajorFunction )
{ KIRQL OldIrql; PIRP Packet; LIST_ENTRY TempList;
InitializeListHead(&TempList);
//
// dispose of all of the queue packets, don't touch the current one though
//
KeAcquireSpinLock(&PacketQueue->Lock,&OldIrql);
Packet=GetUseableIrp(&PacketQueue->ListHead);
while (Packet != NULL) {
PIO_STACK_LOCATION IrpSp=IoGetCurrentIrpStackLocation(Packet);
if ((MajorFunction == 0xff) || (MajorFunction==IrpSp->MajorFunction)) { //
// either the caller wants all of irps completed, or they just want
// this specific type. In any case this is going to get completed
//
KeReleaseSpinLock(&PacketQueue->Lock,OldIrql);
Packet->IoStatus.Status=STATUS_CANCELLED; Packet->IoStatus.Information=0;
IoCompleteRequest(Packet,IO_NO_INCREMENT);
KeAcquireSpinLock(&PacketQueue->Lock,&OldIrql);
} else { //
// this one does not need to be completed, put it on the temp list
//
InsertHeadList(&TempList,&Packet->Tail.Overlay.ListEntry);
}
Packet=GetUseableIrp(&PacketQueue->ListHead); }
while (!IsListEmpty(&TempList)) { //
// move all the irps on the temp queue back to the real queue
//
PLIST_ENTRY ListEntry;
ListEntry=RemoveTailList(&TempList);
InsertHeadList(&PacketQueue->ListHead,ListEntry); }
KeReleaseSpinLock(&PacketQueue->Lock,OldIrql);
return; }
|