803 lines
19 KiB
C
803 lines
19 KiB
C
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
queue.c
|
|
|
|
Abstract:
|
|
|
|
This module implements IRP queue processing routines for ws2ifsl.sys driver.
|
|
|
|
Author:
|
|
|
|
Vadim Eydelman (VadimE) Dec-1996
|
|
|
|
Revision History:
|
|
|
|
Vadim Eydelman (VadimE) Oct-1997, rewrite to properly handle IRP
|
|
cancellation
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
|
|
//
|
|
// Private prototypes
|
|
//
|
|
|
|
VOID
|
|
QueueKernelRoutine (
|
|
IN struct _KAPC *Apc,
|
|
IN OUT PKNORMAL_ROUTINE *NormalRoutine,
|
|
IN OUT PVOID *NormalContext,
|
|
IN OUT PVOID *SystemArgument1,
|
|
IN OUT PVOID *SystemArgument2
|
|
);
|
|
|
|
VOID
|
|
SignalRequest (
|
|
IN PIFSL_PROCESS_CTX ProcessCtx
|
|
);
|
|
|
|
VOID
|
|
RequestRundownRoutine (
|
|
IN struct _KAPC *Apc
|
|
);
|
|
|
|
VOID
|
|
FlushRequestQueue (
|
|
PIFSL_QUEUE Queue
|
|
);
|
|
|
|
VOID
|
|
QueuedCancelRoutine (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
VOID
|
|
SignalCancel (
|
|
IN PIFSL_PROCESS_CTX ProcessCtx
|
|
);
|
|
|
|
VOID
|
|
CancelRundownRoutine (
|
|
IN struct _KAPC *Apc
|
|
);
|
|
|
|
VOID
|
|
FlushCancelQueue (
|
|
PIFSL_QUEUE Queue
|
|
);
|
|
|
|
|
|
|
|
#pragma alloc_text(PAGE, InitializeRequestQueue)
|
|
#pragma alloc_text(PAGE, InitializeCancelQueue)
|
|
|
|
VOID
|
|
InitializeRequestQueue (
|
|
IN PIFSL_PROCESS_CTX ProcessCtx,
|
|
IN PKTHREAD ApcThread,
|
|
IN KPROCESSOR_MODE ApcMode,
|
|
IN PKNORMAL_ROUTINE ApcRoutine,
|
|
IN PVOID ApcContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes request queue object
|
|
|
|
Arguments:
|
|
ProcessCtx - process context to which queue belongs
|
|
ApcThread - thread to which to queue APC requests for processing
|
|
ApcMode - mode of the caller (should be user)
|
|
ApcRoutine - routine that processes requests
|
|
ApcContext - context to pass to the routine in addition to request
|
|
parameters
|
|
|
|
Return Value:
|
|
None
|
|
--*/
|
|
{
|
|
PAGED_CODE ();
|
|
|
|
InitializeListHead (&ProcessCtx->RequestQueue.ListHead);
|
|
ProcessCtx->RequestQueue.Busy = FALSE;
|
|
KeInitializeSpinLock (&ProcessCtx->RequestQueue.Lock);
|
|
KeInitializeApc (&ProcessCtx->RequestQueue.Apc,
|
|
ApcThread,
|
|
OriginalApcEnvironment,
|
|
QueueKernelRoutine,
|
|
RequestRundownRoutine,
|
|
ApcRoutine,
|
|
ApcMode,
|
|
ApcContext);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
QueueRequest (
|
|
IN PIFSL_PROCESS_CTX ProcessCtx,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Queues IRP to IFSL request queue and signals to user mode DLL
|
|
to start processing if it is not busy already.
|
|
|
|
Arguments:
|
|
ProcessCtx - process context in which to queue
|
|
Irp - request to be queued
|
|
|
|
Return Value:
|
|
TRUE - IRP was queued
|
|
FALSE - IRP was already cancelled
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN res;
|
|
KIRQL oldIRQL;
|
|
PIFSL_QUEUE queue = &ProcessCtx->RequestQueue;
|
|
|
|
IoSetCancelRoutine (Irp, QueuedCancelRoutine);
|
|
KeAcquireSpinLock (&queue->Lock, &oldIRQL);
|
|
if (!Irp->Cancel) {
|
|
//
|
|
// Request is not cancelled, insert it into the queue
|
|
//
|
|
InsertTailList (&queue->ListHead, &Irp->Tail.Overlay.ListEntry);
|
|
Irp->Tail.Overlay.IfslRequestQueue = queue;
|
|
|
|
//
|
|
// If queue wasn't busy, signal to user mode DLL to pick up new request
|
|
//
|
|
if (!queue->Busy) {
|
|
ASSERT (queue->ListHead.Flink==&Irp->Tail.Overlay.ListEntry);
|
|
SignalRequest (ProcessCtx);
|
|
ASSERT (queue->Busy);
|
|
}
|
|
res = TRUE;
|
|
}
|
|
else {
|
|
res = FALSE;
|
|
}
|
|
KeReleaseSpinLock (&queue->Lock, oldIRQL);
|
|
|
|
return res;
|
|
|
|
} // QueueRequest
|
|
|
|
PIRP
|
|
DequeueRequest (
|
|
PIFSL_PROCESS_CTX ProcessCtx,
|
|
ULONG UniqueId,
|
|
BOOLEAN *more
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes IRP from IFSL request queue.
|
|
|
|
Arguments:
|
|
ProcessCtx - process context from which to remove
|
|
UniqueId - unique request id
|
|
more - set to TRUE if there are more requests in the queue
|
|
|
|
Return Value:
|
|
IRP - pointer to the IRP
|
|
NULL - the request was not in the queue
|
|
|
|
--*/
|
|
{
|
|
KIRQL oldIRQL;
|
|
PIRP irp;
|
|
PIFSL_QUEUE queue = &ProcessCtx->RequestQueue;
|
|
|
|
KeAcquireSpinLock (&queue->Lock, &oldIRQL);
|
|
irp = CONTAINING_RECORD (queue->ListHead.Flink, IRP, Tail.Overlay.ListEntry);
|
|
if (!IsListEmpty (&queue->ListHead)
|
|
&& (irp->Tail.Overlay.IfslRequestId==UlongToPtr(UniqueId))) {
|
|
//
|
|
// Queue is not empty and first request matches passed in parameters,
|
|
// dequeue and return it
|
|
//
|
|
|
|
ASSERT (queue->Busy);
|
|
|
|
RemoveEntryList (&irp->Tail.Overlay.ListEntry);
|
|
irp->Tail.Overlay.IfslRequestQueue = NULL;
|
|
}
|
|
else {
|
|
irp = NULL;
|
|
}
|
|
|
|
if (IsListEmpty (&queue->ListHead)) {
|
|
//
|
|
// Queue is now empty, change its state, so that new request knows to
|
|
// signal to user mode DLL
|
|
//
|
|
queue->Busy = FALSE;
|
|
}
|
|
else {
|
|
//
|
|
// There is another request pending, signal it now
|
|
//
|
|
SignalRequest (ProcessCtx);
|
|
ASSERT (queue->Busy);
|
|
}
|
|
//
|
|
// Hint the caller that we just signalled, so it does not have to wait on event
|
|
//
|
|
*more = queue->Busy;
|
|
|
|
KeReleaseSpinLock (&queue->Lock, oldIRQL);
|
|
return irp;
|
|
}
|
|
|
|
|
|
VOID
|
|
SignalRequest (
|
|
IN PIFSL_PROCESS_CTX ProcessCtx
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fills request parameters & signals user mode DLL to process the request
|
|
|
|
Arguments:
|
|
ProcessCtx - our context for the process which IRP belongs to
|
|
|
|
Return Value:
|
|
None
|
|
Note:
|
|
SHOULD ONLY BE CALLED WITH QUEUE SPINLOCK HELD
|
|
--*/
|
|
{
|
|
PIRP irp;
|
|
PIO_STACK_LOCATION irpSp;
|
|
ULONG bufferLen;
|
|
|
|
ASSERT (!IsListEmpty (&ProcessCtx->RequestQueue.ListHead));
|
|
|
|
|
|
irp = CONTAINING_RECORD (
|
|
ProcessCtx->RequestQueue.ListHead.Flink,
|
|
IRP,
|
|
Tail.Overlay.ListEntry
|
|
);
|
|
irpSp = IoGetCurrentIrpStackLocation (irp);
|
|
|
|
switch (irpSp->MajorFunction) {
|
|
case IRP_MJ_READ:
|
|
bufferLen = irpSp->Parameters.Read.Length;;
|
|
break;
|
|
case IRP_MJ_WRITE:
|
|
bufferLen = irpSp->Parameters.Write.Length;
|
|
break;
|
|
case IRP_MJ_DEVICE_CONTROL:
|
|
switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
|
|
case IOCTL_AFD_RECEIVE_DATAGRAM:
|
|
bufferLen = ADDR_ALIGN(irpSp->Parameters.DeviceIoControl.OutputBufferLength)
|
|
+ irpSp->Parameters.DeviceIoControl.InputBufferLength;
|
|
break;
|
|
case IOCTL_AFD_RECEIVE:
|
|
bufferLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
break;
|
|
case IOCTL_AFD_SEND_DATAGRAM:
|
|
bufferLen = ADDR_ALIGN(irpSp->Parameters.DeviceIoControl.OutputBufferLength)
|
|
+ irpSp->Parameters.DeviceIoControl.InputBufferLength;
|
|
break;
|
|
}
|
|
break;
|
|
case IRP_MJ_PNP:
|
|
bufferLen = sizeof (HANDLE);
|
|
break;
|
|
default:
|
|
ASSERT (FALSE);
|
|
break;
|
|
}
|
|
|
|
if (KeInsertQueueApc (&ProcessCtx->RequestQueue.Apc,
|
|
irp->Tail.Overlay.IfslRequestId,
|
|
UlongToPtr(bufferLen),
|
|
IO_NETWORK_INCREMENT)) {
|
|
WsProcessPrint (ProcessCtx, DBG_QUEUE,
|
|
("WS2IFSL-%04lx SignalRequest: Irp %p (id %ld) on socket %p.\n",
|
|
PsGetCurrentProcessId(),
|
|
irp, irp->Tail.Overlay.IfslRequestId,
|
|
irpSp->FileObject));
|
|
ProcessCtx->RequestQueue.Busy = TRUE;
|
|
}
|
|
else {
|
|
WsProcessPrint (ProcessCtx, DBG_QUEUE|DBG_FAILURES,
|
|
("WS2IFSL-%04lx KeInsertQueueApc failed: Irp %p (id %ld) on socket %p.\n",
|
|
PsGetCurrentProcessId(),
|
|
irp, irp->Tail.Overlay.IfslRequestId,
|
|
irpSp->FileObject));
|
|
//
|
|
// APC queing failed, cancel all outstanding requests.
|
|
//
|
|
FlushRequestQueue (&ProcessCtx->RequestQueue);
|
|
}
|
|
|
|
} // SignalRequest
|
|
|
|
VOID
|
|
QueueKernelRoutine (
|
|
IN struct _KAPC *Apc,
|
|
IN OUT PKNORMAL_ROUTINE *NormalRoutine,
|
|
IN OUT PVOID *NormalContext,
|
|
IN OUT PVOID *SystemArgument1,
|
|
IN OUT PVOID *SystemArgument2
|
|
)
|
|
{
|
|
NOTHING;
|
|
}
|
|
|
|
VOID
|
|
RequestRundownRoutine (
|
|
IN struct _KAPC *Apc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
APC rundown routine for request queue APC
|
|
Flushes the queue and marks it as not busy so new
|
|
request fail immediately as well.
|
|
Arguments:
|
|
APC - cancel queue APC structure
|
|
Return Value:
|
|
None
|
|
--*/
|
|
{
|
|
PIFSL_QUEUE Queue;
|
|
KIRQL oldIrql;
|
|
|
|
Queue = CONTAINING_RECORD (Apc, IFSL_QUEUE, Apc);
|
|
KeAcquireSpinLock (&Queue->Lock, &oldIrql);
|
|
Queue->Busy = FALSE;
|
|
FlushRequestQueue (Queue);
|
|
KeReleaseSpinLock (&Queue->Lock, oldIrql);
|
|
}
|
|
|
|
|
|
VOID
|
|
FlushRequestQueue (
|
|
PIFSL_QUEUE Queue
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Flushes and completes IRPs in the request queue
|
|
Arguments:
|
|
Queue - request queue to flush
|
|
Return Value:
|
|
None
|
|
Note:
|
|
SHOULD ONLY BE CALLED WITH QUEUE SPINLOCK HELD
|
|
--*/
|
|
{
|
|
while (!IsListEmpty (&Queue->ListHead)) {
|
|
PIRP irp = CONTAINING_RECORD (Queue->ListHead.Flink,
|
|
IRP,
|
|
Tail.Overlay.ListEntry);
|
|
RemoveEntryList (&irp->Tail.Overlay.ListEntry);
|
|
irp->Tail.Overlay.IfslRequestQueue = NULL;
|
|
KeReleaseSpinLockFromDpcLevel (&Queue->Lock);
|
|
irp->IoStatus.Information = 0;
|
|
irp->IoStatus.Status = STATUS_CANCELLED;
|
|
CompleteSocketIrp (irp);
|
|
KeAcquireSpinLockAtDpcLevel (&Queue->Lock);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
CleanupQueuedRequests (
|
|
IN PIFSL_PROCESS_CTX ProcessCtx,
|
|
IN PFILE_OBJECT SocketFile,
|
|
OUT PLIST_ENTRY IrpList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Cleans up all IRPs associated with a socket file object from the request
|
|
queue
|
|
|
|
Arguments:
|
|
ProcessCtx - process context to which queue belongs
|
|
SocketFile - socket file object for which to remove requests
|
|
IrpList - list head to hold the IRPs removed from the queue
|
|
|
|
Return Value:
|
|
None
|
|
--*/
|
|
{
|
|
KIRQL oldIRQL;
|
|
PLIST_ENTRY entry;
|
|
PIFSL_QUEUE queue = &ProcessCtx->RequestQueue;
|
|
|
|
KeAcquireSpinLock (&queue->Lock, &oldIRQL);
|
|
entry = queue->ListHead.Flink;
|
|
while (entry!=&queue->ListHead) {
|
|
PIRP irp = CONTAINING_RECORD (entry, IRP, Tail.Overlay.ListEntry);
|
|
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (irp);
|
|
|
|
entry = entry->Flink;
|
|
if (irpSp->FileObject==SocketFile) {
|
|
RemoveEntryList (&irp->Tail.Overlay.ListEntry);
|
|
irp->Tail.Overlay.IfslRequestQueue = NULL;
|
|
InsertTailList (IrpList, &irp->Tail.Overlay.ListEntry);
|
|
}
|
|
}
|
|
KeReleaseSpinLock (&queue->Lock, oldIRQL);
|
|
}
|
|
|
|
VOID
|
|
QueuedCancelRoutine (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Driver cancel routine for socket request waiting in the queue
|
|
to be reported to user mode DLL.
|
|
|
|
Arguments:
|
|
DeviceObject - WS2IFSL device object
|
|
Irp - Irp to be cancelled
|
|
|
|
Return Value:
|
|
None
|
|
--*/
|
|
{
|
|
PIO_STACK_LOCATION irpSp;
|
|
PIFSL_SOCKET_CTX SocketCtx;
|
|
PIFSL_PROCESS_CTX ProcessCtx;
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation (Irp);
|
|
|
|
SocketCtx = irpSp->FileObject->FsContext;
|
|
ProcessCtx = SocketCtx->ProcessRef->FsContext;
|
|
|
|
WsProcessPrint (ProcessCtx, DBG_QUEUE,
|
|
("WS2IFSL-%04lx CancelQueuedRequest: Socket %p , Irp %p\n",
|
|
PsGetCurrentProcessId(),
|
|
irpSp->FileObject, Irp));
|
|
KeAcquireSpinLockAtDpcLevel (&ProcessCtx->RequestQueue.Lock);
|
|
if (Irp->Tail.Overlay.IfslRequestQueue!=NULL) {
|
|
ASSERT (Irp->Tail.Overlay.IfslRequestQueue==&ProcessCtx->RequestQueue);
|
|
//
|
|
// Request was in the queue, remove and cancel it here
|
|
//
|
|
RemoveEntryList (&Irp->Tail.Overlay.ListEntry);
|
|
Irp->Tail.Overlay.IfslRequestQueue = NULL;
|
|
KeReleaseSpinLockFromDpcLevel (&ProcessCtx->RequestQueue.Lock);
|
|
IoReleaseCancelSpinLock (Irp->CancelIrql);
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
Irp->IoStatus.Status = STATUS_CANCELLED;
|
|
CompleteSocketIrp (Irp);
|
|
}
|
|
else {
|
|
//
|
|
// Request was not in the queue, whoever removed should note the
|
|
// cancel flag and properly deal with it
|
|
//
|
|
KeReleaseSpinLockFromDpcLevel (&ProcessCtx->RequestQueue.Lock);
|
|
IoReleaseCancelSpinLock (Irp->CancelIrql);
|
|
//
|
|
// Don't touch IRP after this as we do not own it anymore
|
|
//
|
|
}
|
|
}
|
|
|
|
VOID
|
|
InitializeCancelQueue (
|
|
IN PIFSL_PROCESS_CTX ProcessCtx,
|
|
IN PKTHREAD ApcThread,
|
|
IN KPROCESSOR_MODE ApcMode,
|
|
IN PKNORMAL_ROUTINE ApcRoutine,
|
|
IN PVOID ApcContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes cancel queue object
|
|
|
|
Arguments:
|
|
ProcessCtx - process context to which queue belongs
|
|
ApcThread - thread to which to queue APC requests for processing
|
|
ApcMode - mode of the caller (should be user)
|
|
ApcRoutine - routine that processes requests
|
|
ApcContext - context to pass to the routine in addition to request
|
|
parameters
|
|
|
|
Return Value:
|
|
None
|
|
--*/
|
|
{
|
|
PAGED_CODE ();
|
|
|
|
InitializeListHead (&ProcessCtx->CancelQueue.ListHead);
|
|
ProcessCtx->CancelQueue.Busy = FALSE;
|
|
KeInitializeSpinLock (&ProcessCtx->CancelQueue.Lock);
|
|
KeInitializeApc (&ProcessCtx->CancelQueue.Apc,
|
|
ApcThread,
|
|
OriginalApcEnvironment,
|
|
QueueKernelRoutine,
|
|
CancelRundownRoutine,
|
|
ApcRoutine,
|
|
ApcMode,
|
|
ApcContext);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
QueueCancel (
|
|
IN PIFSL_PROCESS_CTX ProcessCtx,
|
|
IN PIFSL_CANCEL_CTX CancelCtx
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Queues cancel request to IFSL cancel queue and signals to user mode DLL
|
|
to start processing if it is not busy already.
|
|
|
|
Arguments:
|
|
ProcessCtx - process context in which to queue
|
|
CancelCtx - request to be queued
|
|
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
{
|
|
KIRQL oldIRQL;
|
|
PIFSL_QUEUE queue = &ProcessCtx->CancelQueue;
|
|
|
|
KeAcquireSpinLock (&queue->Lock, &oldIRQL);
|
|
InsertTailList (&queue->ListHead, &CancelCtx->ListEntry);
|
|
ASSERT (CancelCtx->ListEntry.Flink != NULL);
|
|
if (!queue->Busy) {
|
|
ASSERT (queue->ListHead.Flink==&CancelCtx->ListEntry);
|
|
SignalCancel (ProcessCtx);
|
|
ASSERT (ProcessCtx->CancelQueue.Busy);
|
|
}
|
|
KeReleaseSpinLock (&queue->Lock, oldIRQL);
|
|
|
|
} // QueueCancel
|
|
|
|
|
|
PIFSL_CANCEL_CTX
|
|
DequeueCancel (
|
|
PIFSL_PROCESS_CTX ProcessCtx,
|
|
ULONG UniqueId,
|
|
BOOLEAN *more
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes cancel request from IFSL cancel queue.
|
|
|
|
Arguments:
|
|
ProcessCtx - process context from which to remove
|
|
UniqueId - unique cancel request id
|
|
more - set to TRUE if there are more requests in the queue
|
|
|
|
Return Value:
|
|
CTX - pointer to cancel request context
|
|
NULL - the request was not in the queue
|
|
|
|
--*/
|
|
{
|
|
KIRQL oldIRQL;
|
|
PIFSL_CANCEL_CTX cancelCtx;
|
|
PIFSL_QUEUE queue = &ProcessCtx->CancelQueue;
|
|
|
|
|
|
KeAcquireSpinLock (&queue->Lock, &oldIRQL);
|
|
cancelCtx = CONTAINING_RECORD (
|
|
queue->ListHead.Flink,
|
|
IFSL_CANCEL_CTX,
|
|
ListEntry
|
|
);
|
|
if (!IsListEmpty (&queue->ListHead)
|
|
&& (cancelCtx->UniqueId==UniqueId)) {
|
|
//
|
|
// Queue is not empty and first request matches passed in parameters,
|
|
// dequeue and return it
|
|
//
|
|
|
|
ASSERT (queue->Busy);
|
|
|
|
RemoveEntryList (&cancelCtx->ListEntry);
|
|
cancelCtx->ListEntry.Flink = NULL;
|
|
}
|
|
else
|
|
cancelCtx = NULL;
|
|
|
|
if (IsListEmpty (&queue->ListHead)) {
|
|
//
|
|
// Queue is now empty, change its state, so that new request knows to
|
|
// signal to user mode DLL
|
|
//
|
|
queue->Busy = FALSE;
|
|
}
|
|
else {
|
|
//
|
|
// There is another request pending, signal it now
|
|
//
|
|
SignalCancel (ProcessCtx);
|
|
ASSERT (queue->Busy);
|
|
}
|
|
//
|
|
// Hint the caller that we just signalled, so it does not have to wait on event
|
|
//
|
|
*more = queue->Busy;
|
|
|
|
KeReleaseSpinLock (&queue->Lock, oldIRQL);
|
|
return cancelCtx;
|
|
}
|
|
|
|
|
|
VOID
|
|
SignalCancel (
|
|
IN PIFSL_PROCESS_CTX ProcessCtx
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fills request parameters & signals user mode DLL to process the request
|
|
|
|
Arguments:
|
|
ProcessCtx - our context for the process which cancel request belongs to
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Note:
|
|
SHOULD ONLY BE CALLED WITH QUEUE SPINLOCK HELD
|
|
|
|
--*/
|
|
{
|
|
PIFSL_CANCEL_CTX cancelCtx;
|
|
PIFSL_SOCKET_CTX SocketCtx;
|
|
|
|
ASSERT (!IsListEmpty (&ProcessCtx->CancelQueue.ListHead));
|
|
|
|
ProcessCtx->CancelQueue.Busy = TRUE;
|
|
|
|
cancelCtx = CONTAINING_RECORD (
|
|
ProcessCtx->CancelQueue.ListHead.Flink,
|
|
IFSL_CANCEL_CTX,
|
|
ListEntry
|
|
);
|
|
SocketCtx = cancelCtx->SocketFile->FsContext;
|
|
|
|
if (KeInsertQueueApc (&ProcessCtx->CancelQueue.Apc,
|
|
UlongToPtr(cancelCtx->UniqueId),
|
|
SocketCtx->DllContext,
|
|
IO_NETWORK_INCREMENT)) {
|
|
WsProcessPrint (ProcessCtx, DBG_QUEUE,
|
|
("WS2IFSL-%04lx SignalCancel: Context %p on socket %p (h %p).\n",
|
|
PsGetCurrentProcessId(),
|
|
cancelCtx, cancelCtx->SocketFile, SocketCtx->DllContext));
|
|
}
|
|
else {
|
|
//
|
|
// APC queing failed, cancel all outstanding requests.
|
|
//
|
|
FlushCancelQueue (&ProcessCtx->CancelQueue);
|
|
}
|
|
|
|
} // SignalCancel
|
|
|
|
VOID
|
|
FlushCancelQueue (
|
|
PIFSL_QUEUE Queue
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Flushes and frees entries in the cancel queue
|
|
Arguments:
|
|
Queue - request queue to flush
|
|
Return Value:
|
|
None
|
|
Note:
|
|
SHOULD ONLY BE CALLED WITH QUEUE SPINLOCK HELD
|
|
--*/
|
|
{
|
|
while (!IsListEmpty (&Queue->ListHead)) {
|
|
PIFSL_CANCEL_CTX cancelCtx = CONTAINING_RECORD (
|
|
Queue->ListHead.Flink,
|
|
IFSL_CANCEL_CTX,
|
|
ListEntry
|
|
);
|
|
RemoveEntryList (&cancelCtx->ListEntry);
|
|
cancelCtx->ListEntry.Flink = NULL;
|
|
FreeSocketCancel (cancelCtx);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
CancelRundownRoutine (
|
|
IN struct _KAPC *Apc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
APC rundown routine for cancel queue APC
|
|
Flushes the queue and marks it as not busy so new
|
|
request fail immediately as well.
|
|
Arguments:
|
|
APC - cancel queue APC structure
|
|
Return Value:
|
|
None
|
|
--*/
|
|
{
|
|
PIFSL_QUEUE Queue;
|
|
KIRQL oldIrql;
|
|
|
|
Queue = CONTAINING_RECORD (Apc, IFSL_QUEUE, Apc);
|
|
KeAcquireSpinLock (&Queue->Lock, &oldIrql);
|
|
Queue->Busy = FALSE;
|
|
FlushCancelQueue (Queue);
|
|
KeReleaseSpinLock (&Queue->Lock, oldIrql);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
RemoveQueuedCancel (
|
|
PIFSL_PROCESS_CTX ProcessCtx,
|
|
PIFSL_CANCEL_CTX CancelCtx
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Remove cancel request from the cancel queue if it is there
|
|
|
|
Arguments:
|
|
ProcessCtx - process context to which queue belongs
|
|
CancelCtx - request to remove
|
|
|
|
Return Value:
|
|
None
|
|
--*/
|
|
{
|
|
KIRQL oldIRQL;
|
|
BOOLEAN res;
|
|
|
|
|
|
// Acquire queue lock
|
|
KeAcquireSpinLock (&ProcessCtx->CancelQueue.Lock, &oldIRQL);
|
|
res = (CancelCtx->ListEntry.Flink!=NULL);
|
|
if (res) {
|
|
RemoveEntryList (&CancelCtx->ListEntry);
|
|
CancelCtx->ListEntry.Flink = NULL;
|
|
}
|
|
KeReleaseSpinLock (&ProcessCtx->CancelQueue.Lock, oldIRQL);
|
|
return res;
|
|
}
|