Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1111 lines
26 KiB

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
workque.c
Abstract:
This module handles the communication between the NT redirector
FSP and the NT redirector FSD.
It defines routines that queue requests to the FSD, and routines
that remove requests from the FSD work queue.
Author:
Larry Osterman (LarryO) 30-May-1990
Revision History:
30-May-1990 LarryO
Created
--*/
#include "precomp.h"
#pragma hdrstop
VOID
BowserCriticalThreadWorker(
IN PVOID Ctx
);
VOID
BowserDelayedThreadWorker(
IN PVOID Ctx
);
KSPIN_LOCK
BowserIrpContextInterlock = {0};
LIST_ENTRY
BowserIrpContextList = {0};
KSPIN_LOCK
BowserIrpQueueSpinLock = {0};
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, BowserAllocateIrpContext)
#pragma alloc_text(PAGE, BowserFreeIrpContext)
#pragma alloc_text(PAGE, BowserInitializeIrpContext)
#pragma alloc_text(PAGE, BowserpUninitializeIrpContext)
#pragma alloc_text(PAGE, BowserInitializeIrpQueue)
#pragma alloc_text(PAGE, BowserQueueNonBufferRequest)
#pragma alloc_text(INIT, BowserpInitializeIrpQueue)
#pragma alloc_text(PAGE4BROW, BowserUninitializeIrpQueue)
#pragma alloc_text(PAGE4BROW, BowserQueueNonBufferRequestReferenced)
#pragma alloc_text(PAGE4BROW, BowserCancelQueuedIoForFile)
#pragma alloc_text(PAGE4BROW, BowserTimeoutQueuedIrp)
#endif
//
// Variables describing browsers use of a Critical system thread.
//
BOOLEAN BowserCriticalThreadRunning = FALSE;
LIST_ENTRY BowserCriticalThreadQueue;
WORK_QUEUE_ITEM BowserCriticalThreadWorkItem;
VOID
BowserQueueCriticalWorkItem (
IN PWORK_QUEUE_ITEM WorkItem
)
/*++
Routine Description:
This routine queues an item onto the critical work queue.
This routine ensures that at most one critical system thread is consumed
by the browser by actually queing this item onto a browser specific queue
then enqueing a critical work queue item that processes that queue.
Arguments:
WorkItem -- Work item to be processed on the critical work queue.
Return Value:
NONE
--*/
{
KIRQL OldIrql;
//
// Insert the queue entry into the browser specific queue.
//
ACQUIRE_SPIN_LOCK(&BowserIrpQueueSpinLock, &OldIrql);
InsertTailList( &BowserCriticalThreadQueue, &WorkItem->List );
//
// If the browser doesn't have a critical system thread running,
// start one now.
//
if ( !BowserCriticalThreadRunning ) {
//
// Mark that the thread is running now
//
BowserCriticalThreadRunning = TRUE;
RELEASE_SPIN_LOCK(&BowserIrpQueueSpinLock, OldIrql);
ExInitializeWorkItem( &BowserCriticalThreadWorkItem,
BowserCriticalThreadWorker,
NULL );
ExQueueWorkItem(&BowserCriticalThreadWorkItem, CriticalWorkQueue );
} else {
RELEASE_SPIN_LOCK(&BowserIrpQueueSpinLock, OldIrql);
}
}
VOID
BowserCriticalThreadWorker(
IN PVOID Ctx
)
/*++
Routine Description:
This routine processes critical browser workitems.
This routine runs in a critical system thread. It is the only critical
system thread used by the browser.
Arguments:
Ctx - Not used
Return Value:
NONE
--*/
{
KIRQL OldIrql;
PLIST_ENTRY Entry;
PWORK_QUEUE_ITEM WorkItem;
UNREFERENCED_PARAMETER( Ctx );
//
// Loop processing work items
//
while( TRUE ) {
//
// If the queue is empty,
// indicate that this thread is no longer running.
// return.
//
ACQUIRE_SPIN_LOCK(&BowserIrpQueueSpinLock, &OldIrql);
if ( IsListEmpty( &BowserCriticalThreadQueue ) ) {
BowserCriticalThreadRunning = FALSE;
RELEASE_SPIN_LOCK(&BowserIrpQueueSpinLock, OldIrql);
return;
}
//
// Remove an entry from the queue.
//
Entry = RemoveHeadList( &BowserCriticalThreadQueue );
RELEASE_SPIN_LOCK(&BowserIrpQueueSpinLock, OldIrql);
WorkItem = CONTAINING_RECORD(Entry, WORK_QUEUE_ITEM, List);
//
// Call the queued routine
//
(*WorkItem->WorkerRoutine)(WorkItem->Parameter);
}
}
//
// Variables describing browsers use of a Delayed system thread.
//
BOOLEAN BowserDelayedThreadRunning = FALSE;
LIST_ENTRY BowserDelayedThreadQueue;
WORK_QUEUE_ITEM BowserDelayedThreadWorkItem;
VOID
BowserQueueDelayedWorkItem (
IN PWORK_QUEUE_ITEM WorkItem
)
/*++
Routine Description:
This routine queues an item onto the Delayed work queue.
This routine ensures that at most one Delayed system thread is consumed
by the browser by actually queing this item onto a browser specific queue
then enqueing a Delayed work queue item that processes that queue.
Arguments:
WorkItem -- Work item to be processed on the Delayed work queue.
Return Value:
NONE
--*/
{
KIRQL OldIrql;
//
// Insert the queue entry into the browser specific queue.
//
ACQUIRE_SPIN_LOCK(&BowserIrpQueueSpinLock, &OldIrql);
InsertTailList( &BowserDelayedThreadQueue, &WorkItem->List );
//
// If the browser doesn't have a Delayed system thread running,
// start one now.
//
if ( !BowserDelayedThreadRunning ) {
//
// Mark that the thread is running now
//
BowserDelayedThreadRunning = TRUE;
RELEASE_SPIN_LOCK(&BowserIrpQueueSpinLock, OldIrql);
ExInitializeWorkItem( &BowserDelayedThreadWorkItem,
BowserDelayedThreadWorker,
NULL );
ExQueueWorkItem(&BowserDelayedThreadWorkItem, DelayedWorkQueue );
} else {
RELEASE_SPIN_LOCK(&BowserIrpQueueSpinLock, OldIrql);
}
}
VOID
BowserDelayedThreadWorker(
IN PVOID Ctx
)
/*++
Routine Description:
This routine processes Delayed browser workitems.
This routine runs in a Delayed system thread. It is the only Delayed
system thread used by the browser.
Arguments:
Ctx - Not used
Return Value:
NONE
--*/
{
KIRQL OldIrql;
PLIST_ENTRY Entry;
PWORK_QUEUE_ITEM WorkItem;
UNREFERENCED_PARAMETER( Ctx );
//
// Loop processing work items
//
while( TRUE ) {
//
// If the queue is empty,
// indicate that this thread is no longer running.
// return.
//
ACQUIRE_SPIN_LOCK(&BowserIrpQueueSpinLock, &OldIrql);
if ( IsListEmpty( &BowserDelayedThreadQueue ) ) {
BowserDelayedThreadRunning = FALSE;
RELEASE_SPIN_LOCK(&BowserIrpQueueSpinLock, OldIrql);
return;
}
//
// Remove an entry from the queue.
//
Entry = RemoveHeadList( &BowserDelayedThreadQueue );
RELEASE_SPIN_LOCK(&BowserIrpQueueSpinLock, OldIrql);
WorkItem = CONTAINING_RECORD(Entry, WORK_QUEUE_ITEM, List);
//
// Call the queued routine
//
(*WorkItem->WorkerRoutine)(WorkItem->Parameter);
}
}
PIRP_CONTEXT
BowserAllocateIrpContext (
VOID
)
/*++
Routine Description:
Initialize a work queue structure, allocating all structures used for it.
Arguments:
None
Return Value:
PIRP_CONTEXT - Newly allocated Irp Context.
--*/
{
PIRP_CONTEXT IrpContext;
PAGED_CODE();
if ((IrpContext = (PIRP_CONTEXT )ExInterlockedRemoveHeadList(&BowserIrpContextList, &BowserIrpContextInterlock)) == NULL) {
//
// If there are no IRP contexts in the "zone", allocate a new
// Irp context from non paged pool.
//
IrpContext = ALLOCATE_POOL(NonPagedPool, sizeof(IRP_CONTEXT), POOL_IRPCONTEXT);
if (IrpContext == NULL) {
InternalError(("Could not allocate pool for IRP context\n"));
}
return IrpContext;
}
return IrpContext;
}
VOID
BowserFreeIrpContext (
PIRP_CONTEXT IrpContext
)
/*++
Routine Description:
Initialize a work queue structure, allocating all structures used for it.
Arguments:
PIRP_CONTEXT IrpContext - Irp Context to free.
None
Return Value:
--*/
{
PAGED_CODE();
//
// We use the first two longwords of the IRP context as a list entry
// when we free it to the zone.
//
ExInterlockedInsertTailList(&BowserIrpContextList, (PLIST_ENTRY )IrpContext,
&BowserIrpContextInterlock);
}
VOID
BowserInitializeIrpContext (
VOID
)
/*++
Routine Description:
Initialize the Irp Context system
Arguments:
None.
Return Value:
None.
--*/
{
PAGED_CODE();
KeInitializeSpinLock(&BowserIrpContextInterlock);
InitializeListHead(&BowserIrpContextList);
}
VOID
BowserpUninitializeIrpContext(
VOID
)
{
PAGED_CODE();
while (!IsListEmpty(&BowserIrpContextList)) {
PIRP_CONTEXT IrpContext = (PIRP_CONTEXT)RemoveHeadList(&BowserIrpContextList);
FREE_POOL(IrpContext);
}
}
VOID
BowserInitializeIrpQueue(
PIRP_QUEUE Queue
)
{
PAGED_CODE();
InitializeListHead(&Queue->Queue);
}
VOID
BowserUninitializeIrpQueue(
PIRP_QUEUE Queue
)
{
KIRQL OldIrql, CancelIrql;
PDRIVER_CANCEL pDriverCancel;
PLIST_ENTRY Entry;
PIRP Request;
BowserReferenceDiscardableCode( BowserDiscardableCodeSection );
DISCARDABLE_CODE( BowserDiscardableCodeSection );
//
// Now remove this IRP from the request chain.
//
ACQUIRE_SPIN_LOCK(&BowserIrpQueueSpinLock, &OldIrql);
while (!IsListEmpty(&Queue->Queue)) {
Entry = RemoveHeadList(&Queue->Queue);
Request = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
// clear cancel routine
Request->IoStatus.Information = 0;
Request->Cancel = FALSE;
pDriverCancel = IoSetCancelRoutine(Request, NULL);
// Set to NULL in the cancel routine under BowserIrpQueueSpinLock protection.
if ( pDriverCancel ) {
RELEASE_SPIN_LOCK(&BowserIrpQueueSpinLock, OldIrql);
BowserCompleteRequest(Request, STATUS_CANCELLED);
ACQUIRE_SPIN_LOCK(&BowserIrpQueueSpinLock, &OldIrql);
}
// otherwise the cancel routine is running at the moment.
}
ASSERT (IsListEmpty(&Queue->Queue));
//
// Make sure no more entries are inserted on this queue.
//
Queue->Queue.Flink = NULL;
Queue->Queue.Blink = NULL;
RELEASE_SPIN_LOCK(&BowserIrpQueueSpinLock, OldIrql);
BowserDereferenceDiscardableCode( BowserDiscardableCodeSection );
}
VOID
BowserCancelQueuedRequest(
IN PDEVICE_OBJECT DeviceObject OPTIONAL,
IN PIRP Irp
)
/*++
Routine Description:
This routine will cancel a queued IRP.
Arguments:
IN PIRP Irp - Supplies the IRP to cancel.
IN PKSPIN_LOCK SpinLock - Supplies a pointer to the spin lock protecting the
queue
IN PLIST_ENTRY Queue - Supplies a pointer to the head of the queue.
Note: See bug history for more: 294055, 306281, 124178, 124180, 131773...
--*/
{
KIRQL OldIrql;
KIRQL CancelIrql;
PLIST_ENTRY Entry, NextEntry;
PIRP Request;
PIRP_QUEUE Queue;
PIO_STACK_LOCATION NextStack = IoGetNextIrpStackLocation(Irp);
LIST_ENTRY CancelList;
ASSERT ( Irp->CancelRoutine == NULL );
InitializeListHead(&CancelList);
//
// Release IOmgr set cancel IRP spinlock & acquire the local
// queue protection spinlock. Then reaquire the cancel spinlock.
// This is the proper lock order.
//
IoReleaseCancelSpinLock( Irp->CancelIrql );
ACQUIRE_SPIN_LOCK(&BowserIrpQueueSpinLock, &OldIrql);
IoAcquireCancelSpinLock( &CancelIrql );
//
// Now remove this IRP from the request chain.
//
//
// A pointer to the queue is stored in the next stack location.
//
Queue = (PIRP_QUEUE)NextStack->Parameters.Others.Argument4;
if (Queue != NULL && Queue->Queue.Flink != NULL) {
for (Entry = Queue->Queue.Flink ;
Entry != &Queue->Queue ;
Entry = NextEntry) {
Request = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
if (Request->Cancel) {
// we're in a cancel routine so the global cancel spinlock is locked
NextEntry = Entry->Flink;
RemoveEntryList(Entry);
Request->IoStatus.Information = 0;
Request->IoStatus.Status = STATUS_CANCELLED;
IoSetCancelRoutine(Request, NULL);
InsertTailList(&CancelList,Entry);
} else {
NextEntry = Entry->Flink;
}
}
}
IoReleaseCancelSpinLock( CancelIrql );
RELEASE_SPIN_LOCK(&BowserIrpQueueSpinLock, OldIrql);
while (!IsListEmpty(&CancelList)) {
Entry = RemoveHeadList(&CancelList);
Request = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
BowserCompleteRequest(Request, Request->IoStatus.Status);
}
UNREFERENCED_PARAMETER(DeviceObject);
}
NTSTATUS
BowserQueueNonBufferRequest(
IN PIRP Irp,
IN PIRP_QUEUE Queue,
IN PDRIVER_CANCEL CancelRoutine
)
/*++
Routine Description:
Queue an IRP in the specified queue.
This routine cannot be called at an IRQ level above APC_LEVEL.
Arguments:
Irp - Supplies the IRP to queue.
Queue - Supplies a pointer to the head of the queue.
CancelRoutine - Address of routine to call if the IRP is cancelled.
--*/
{
NTSTATUS Status;
//
// This routine itself is paged code which calls the discardable code
// in BowserQueueNonBufferRequestReferenced().
//
PAGED_CODE();
BowserReferenceDiscardableCode( BowserDiscardableCodeSection );
DISCARDABLE_CODE( BowserDiscardableCodeSection );
Status = BowserQueueNonBufferRequestReferenced( Irp,
Queue,
CancelRoutine );
BowserDereferenceDiscardableCode( BowserDiscardableCodeSection );
return Status;
}
NTSTATUS
BowserQueueNonBufferRequestReferenced(
IN PIRP Irp,
IN PIRP_QUEUE Queue,
IN PDRIVER_CANCEL CancelRoutine
)
/*++
Routine Description:
Queue an IRP in the specified queue.
This routine can only be called if the BowserDiscardableCodeSection
is already referenced. It can be called at any IRQ level.
Arguments:
Irp - Supplies the IRP to queue.
Queue - Supplies a pointer to the head of the queue.
CancelRoutine - Address of routine to call if the IRP is cancelled.
--*/
{
KIRQL OldIrql, CancelIrql;
LARGE_INTEGER CurrentTickCount;
PIO_STACK_LOCATION NextStackLocation;
BOOL bReleaseSpinlocks;
DISCARDABLE_CODE( BowserDiscardableCodeSection );
// DbgPrint("Queue IRP %lx to queue %lx\n", Irp, Queue);
//
// Insert the request into the request announcement list.
//
ACQUIRE_SPIN_LOCK(&BowserIrpQueueSpinLock, &OldIrql);
if (Queue->Queue.Flink == NULL) {
ASSERT (Queue->Queue.Blink == NULL);
RELEASE_SPIN_LOCK(&BowserIrpQueueSpinLock, OldIrql);
return(STATUS_CANCELLED);
}
//
// Flag that this request is going to be pending.
//
IoMarkIrpPending(Irp);
InsertTailList(&Queue->Queue, &Irp->Tail.Overlay.ListEntry);
//
// Make sure there's room enough in the stack location for this.
//
ASSERT (Irp->CurrentLocation <= Irp->StackCount);
NextStackLocation = IoGetNextIrpStackLocation(Irp);
//
// Stick the current tick count into the next IRP stack location
// for this IRP. This allows us to figure out if these IRP's have been
// around for "too long".
//
// Beware:the IRP stack location is unaligned.
//
KeQueryTickCount( &CurrentTickCount );
*((LARGE_INTEGER UNALIGNED *)&NextStackLocation->Parameters.Others.Argument1) =
CurrentTickCount;
//
// Link the queue into the IRP.
//
NextStackLocation->Parameters.Others.Argument4 = (PVOID)Queue;
// WARNING: double spinlock condition
IoAcquireCancelSpinLock(&CancelIrql);
bReleaseSpinlocks = TRUE;
if (Irp->Cancel) {
//
// The Irp is in cancellable state:
// if CancelRoutine == NULL, the routine is currently running
// Otherwise, we need to cancel it ourselves
//
if ( Irp->CancelRoutine ) {
// cacelable:
// - rm is valid since we're still holding BowserIrpQueueSpinLock
RemoveEntryList( &Irp->Tail.Overlay.ListEntry );
// release spinlocks before completing the request
IoReleaseCancelSpinLock(CancelIrql);
RELEASE_SPIN_LOCK(&BowserIrpQueueSpinLock, OldIrql);
bReleaseSpinlocks = FALSE;
// complete.
BowserCompleteRequest ( Irp, STATUS_CANCELLED );
}
// else CancelRoutine is running
} else {
IoSetCancelRoutine(Irp, CancelRoutine);
}
if ( bReleaseSpinlocks ) {
// release spinlocks
IoReleaseCancelSpinLock(CancelIrql);
RELEASE_SPIN_LOCK(&BowserIrpQueueSpinLock, OldIrql);
}
return STATUS_PENDING;
}
VOID
BowserTimeoutQueuedIrp(
IN PIRP_QUEUE Queue,
IN ULONG NumberOfSecondsToTimeOut
)
/*++
Routine Description:
This routine will scan an IRP queue and time out any requests that have
been on the queue for "too long"
Arguments:
IN PIRP_QUEUE Queue - Supplies the Queue to scan.
IN ULONG NumberOfSecondsToTimeOut - Supplies the number of seconds a request
should remain on the queue.
Return Value:
None
This routine will also complete any canceled queued requests it finds (on
general principles).
--*/
{
PIRP Irp;
KIRQL OldIrql, CancelIrql;
PDRIVER_CANCEL pDriverCancel;
PLIST_ENTRY Entry, NextEntry;
LARGE_INTEGER Timeout;
LIST_ENTRY CancelList;
BowserReferenceDiscardableCode( BowserDiscardableCodeSection );
DISCARDABLE_CODE( BowserDiscardableCodeSection );
InitializeListHead(&CancelList);
//
// Compute the timeout time into 100ns units.
//
Timeout.QuadPart = (LONGLONG)NumberOfSecondsToTimeOut * (LONGLONG)(10000*1000);
//
// Now convert the timeout into a number of ticks.
//
Timeout.QuadPart = Timeout.QuadPart / (LONGLONG)KeQueryTimeIncrement();
ASSERT (Timeout.HighPart == 0);
// DbgPrint("Dequeue irp from queue %lx...", Queue);
ACQUIRE_SPIN_LOCK(&BowserIrpQueueSpinLock, &OldIrql);
for (Entry = Queue->Queue.Flink ;
Entry != &Queue->Queue ;
Entry = NextEntry) {
Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
//
// If the request was canceled, this is a convenient time to cancel
// it.
//
if (Irp->Cancel) {
NextEntry = Entry->Flink;
pDriverCancel = IoSetCancelRoutine(Irp, NULL);
// Set to NULL in the cancel routine under BowserIrpQueueSpinLock protection.
if ( pDriverCancel ) {
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_CANCELLED;
RemoveEntryList(Entry);
InsertTailList(&CancelList,Entry);
}
// otherwise the cancel routine is running at the moment.
//
// Now check to see if this request is "too old". If it is, complete
// it with an error.
//
} else {
PIO_STACK_LOCATION NextIrpStackLocation;
LARGE_INTEGER CurrentTickCount;
LARGE_INTEGER RequestTime;
LARGE_INTEGER Temp;
NextIrpStackLocation = IoGetNextIrpStackLocation(Irp);
//
// Snapshot the current tickcount.
//
KeQueryTickCount(&CurrentTickCount);
//
// Figure out how many seconds this request has been active for
//
Temp.LowPart = (*((LARGE_INTEGER UNALIGNED *)&NextIrpStackLocation->Parameters.Others.Argument1)).LowPart;
Temp.HighPart= (*((LARGE_INTEGER UNALIGNED *)&NextIrpStackLocation->Parameters.Others.Argument1)).HighPart;
RequestTime.QuadPart = CurrentTickCount.QuadPart - Temp.QuadPart;
ASSERT (RequestTime.HighPart == 0);
//
// If this request has lasted "too long", then time it
// out.
//
if (RequestTime.LowPart > Timeout.LowPart) {
NextEntry = Entry->Flink;
pDriverCancel = IoSetCancelRoutine(Irp, NULL);
// Set to NULL in the cancel routine under BowserIrpQueueSpinLock protection.
if ( pDriverCancel ) {
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_IO_TIMEOUT;
RemoveEntryList(Entry);
InsertTailList(&CancelList,Entry);
}
// otherwise it the cancel routine is running
} else {
NextEntry = Entry->Flink;
}
}
}
RELEASE_SPIN_LOCK(&BowserIrpQueueSpinLock, OldIrql);
while (!IsListEmpty(&CancelList)) {
Entry = RemoveHeadList(&CancelList);
Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
BowserCompleteRequest(Irp, Irp->IoStatus.Status);
}
BowserDereferenceDiscardableCode( BowserDiscardableCodeSection );
// DbgPrint("%lx.\n", Irp);
}
PIRP
BowserDequeueQueuedIrp(
IN PIRP_QUEUE Queue
)
{
PIRP Irp;
KIRQL OldIrql;
PLIST_ENTRY IrpEntry;
// DbgPrint("Dequeue irp from queue %lx...", Queue);
ACQUIRE_SPIN_LOCK(&BowserIrpQueueSpinLock, &OldIrql);
if (IsListEmpty(&Queue->Queue)) {
//
// There are no waiting request announcement FsControls, so
// return success.
//
RELEASE_SPIN_LOCK(&BowserIrpQueueSpinLock, OldIrql);
// DbgPrint("No entry found.\n");
return NULL;
}
IrpEntry = RemoveHeadList(&Queue->Queue);
Irp = CONTAINING_RECORD(IrpEntry, IRP, Tail.Overlay.ListEntry);
IoAcquireCancelSpinLock(&Irp->CancelIrql);
//
// Remove the cancel request for this IRP.
//
Irp->Cancel = FALSE;
IoSetCancelRoutine(Irp, NULL);
IoReleaseCancelSpinLock(Irp->CancelIrql);
RELEASE_SPIN_LOCK(&BowserIrpQueueSpinLock, OldIrql);
// DbgPrint("%lx.\n", Irp);
return Irp;
}
VOID
BowserCancelQueuedIoForFile(
IN PIRP_QUEUE Queue,
IN PFILE_OBJECT FileObject
)
{
KIRQL OldIrql;
PLIST_ENTRY Entry, NextEntry;
PDRIVER_CANCEL pDriverCancel;
PIRP Request;
LIST_ENTRY CancelList;
BowserReferenceDiscardableCode( BowserDiscardableCodeSection );
DISCARDABLE_CODE( BowserDiscardableCodeSection );
InitializeListHead(&CancelList);
//
// Walk the outstanding IRP list for this
//
ACQUIRE_SPIN_LOCK(&BowserIrpQueueSpinLock, &OldIrql);
for (Entry = Queue->Queue.Flink ;
Entry != &Queue->Queue ;
Entry = NextEntry) {
Request = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
//
// If the request was canceled, blow it away.
//
if (Request->Cancel) {
NextEntry = Entry->Flink;
// This is the cancel routine setting of cancel routine ptr to NULL.
pDriverCancel = IoSetCancelRoutine(Request, NULL);
// Set to NULL in the cancel routine under BowserIrpQueueSpinLock protection.
if ( pDriverCancel ) {
RemoveEntryList(Entry);
Request->IoStatus.Information = 0;
Request->IoStatus.Status = STATUS_CANCELLED;
InsertTailList(&CancelList,Entry);
}
// otherwise the cancel routine is running currently.
//
// If the request was for this file object, blow it away.
//
} else if (Request->Tail.Overlay.OriginalFileObject == FileObject) {
NextEntry = Entry->Flink;
// This is the cancel routine setting of cancel routine ptr to NULL.
pDriverCancel = IoSetCancelRoutine(Request, NULL);
// Set to NULL in the cancel routine under BowserIrpQueueSpinLock protection.
if ( pDriverCancel ) {
RemoveEntryList(Entry);
Request->IoStatus.Information = 0;
Request->IoStatus.Status = STATUS_FILE_CLOSED;
InsertTailList(&CancelList,Entry);
}
// otherwise the cancel routine is running currently.
} else {
NextEntry = Entry->Flink;
}
}
RELEASE_SPIN_LOCK(&BowserIrpQueueSpinLock, OldIrql);
while (!IsListEmpty(&CancelList)) {
Entry = RemoveHeadList(&CancelList);
Request = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
BowserCompleteRequest(Request, Request->IoStatus.Status);
}
BowserDereferenceDiscardableCode( BowserDiscardableCodeSection );
}
VOID
BowserpInitializeIrpQueue(
VOID
)
{
KeInitializeSpinLock(&BowserIrpQueueSpinLock);
InitializeListHead( &BowserCriticalThreadQueue );
InitializeListHead( &BowserDelayedThreadQueue );
}