Worker Thread Problems

I have a completion routine that needs to be run at Irql Passive. To
handle those cases where the Irql is higher I pass off the processing to a
worker thread. Having read in OSR’s Win2K/XP IFS FAQ that you shouldn’t
wait in completion for worker to finish (couldn’t figure out how anyway
since at least one call to set up and wait required an “Irql must be
passive” function in every scenario I could come up with.) I rewrote my
Dispatch routine to wait instead.

Problem is sometimes I’m getting a KMODE_EXCEPTION -
STATUS_ACCESS_VIOLATION when touching Irp stuff which leads me to believe
that sometimes the Irp has been torn down before my worker thread gets to
it. Not good.

Am thinking the status I return in the completion routine might be problem
but don’t think STATUS_MORE_PROCESSING_REQUIRED is appropriate here since,
among other things, I didn’t create the Irp and therefore wouldn’t feel
comfortable Completing it.

Here’s a rough sketch of what I’m doing. Any insights would be much
appreciated:

DISPATCH:

IoCopyCurrentIrpStackLocationToNext(Irp);

pEvent = ExAllocatePool( NonPagedPool, sizeof(KEVENT));

if (pEvent)
{
KeInitializeEvent(pEvent, SynchronizationEvent, FALSE);
IoSetCompletionRoutine(
Irp,
CreateCompletion,
pEvent, //context
TRUE,
TRUE,
TRUE);

(void) IoCallDriver(pDeviceExtension->NextDeviceObject, Irp);
KeWaitForSingleObject(pEvent, Executive, KernelMode, TRUE, 0);
ExFreePool(pEvent);
return Irp->IoStatus.Status;
}

COMPLETION:

pWData = ExAllocatePool( NonPagedPool, sizeof(WORK_DATA));
if (pWData)
{
pIOWorkItem = IoAllocateWorkItem( DeviceObject );
pWData->DeviceObject = DeviceObject;
pWData->Irp = Irp;
pWData->pIOWorkItem = pIOWorkItem;
pWData->pIrpStack = pIrpStack;
pWData->pEvent = Context;
IoQueueWorkItem( pIOWorkItem, &WorkerCreateFilter, CriticalWorkQueue,
(PVOID) pWData);
}
}

if (Irp->PendingReturned)
{
IoMarkIrpPending( Irp );
}

return STATUS_SUCCESS;

WORKER:
//Do processing, then… (problem (sometimes): KMODE_EXCEPTION -
STATUS_ACCESS_VIOLATION Irp already torn down?)

KeSetEvent(pWData->pEvent, 0 , FALSE);
IoFreeWorkItem(pWData->pIOWorkItem);
ExFreePool(pWData);

You must mark the IRP pending before you put it in the queue. Your
thread is pulling the item from the queue and completing it before you
call IoMarkIrpPending(). This is why the IRP is invalid.

Classic race condition :slight_smile:

Jamey Kirby
StorageCraft, inc.
xxxxx@storagecraft.com
www.storagecraft.com

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@yahoo.com
Sent: Tuesday, March 26, 2002 9:42 AM
To: File Systems Developers
Subject: [ntfsd] Worker Thread Problems

I have a completion routine that needs to be run at Irql Passive. To
handle those cases where the Irql is higher I pass off the processing to
a
worker thread. Having read in OSR’s Win2K/XP IFS FAQ that you shouldn’t
wait in completion for worker to finish (couldn’t figure out how anyway
since at least one call to set up and wait required an “Irql must be
passive” function in every scenario I could come up with.) I rewrote my
Dispatch routine to wait instead.

Problem is sometimes I’m getting a KMODE_EXCEPTION -
STATUS_ACCESS_VIOLATION when touching Irp stuff which leads me to
believe
that sometimes the Irp has been torn down before my worker thread gets
to
it. Not good.

Am thinking the status I return in the completion routine might be
problem
but don’t think STATUS_MORE_PROCESSING_REQUIRED is appropriate here
since,
among other things, I didn’t create the Irp and therefore wouldn’t feel
comfortable Completing it.

Here’s a rough sketch of what I’m doing. Any insights would be much
appreciated:

DISPATCH:

IoCopyCurrentIrpStackLocationToNext(Irp);

pEvent = ExAllocatePool( NonPagedPool, sizeof(KEVENT));

if (pEvent)
{
KeInitializeEvent(pEvent, SynchronizationEvent, FALSE);
IoSetCompletionRoutine(
Irp,
CreateCompletion,
pEvent, //context
TRUE,
TRUE,
TRUE);

(void) IoCallDriver(pDeviceExtension->NextDeviceObject, Irp);
KeWaitForSingleObject(pEvent, Executive, KernelMode, TRUE, 0);
ExFreePool(pEvent);
return Irp->IoStatus.Status;
}

COMPLETION:

pWData = ExAllocatePool( NonPagedPool, sizeof(WORK_DATA));
if (pWData)
{
pIOWorkItem = IoAllocateWorkItem( DeviceObject );
pWData->DeviceObject = DeviceObject;
pWData->Irp = Irp;
pWData->pIOWorkItem = pIOWorkItem;
pWData->pIrpStack = pIrpStack;
pWData->pEvent = Context;
IoQueueWorkItem( pIOWorkItem, &WorkerCreateFilter,
CriticalWorkQueue,
(PVOID) pWData);
}
}

if (Irp->PendingReturned)
{
IoMarkIrpPending( Irp );
}

return STATUS_SUCCESS;

WORKER:
//Do processing, then… (problem (sometimes): KMODE_EXCEPTION -
STATUS_ACCESS_VIOLATION Irp already torn down?)

KeSetEvent(pWData->pEvent, 0 , FALSE);
IoFreeWorkItem(pWData->pIOWorkItem);
ExFreePool(pWData);


You are currently subscribed to ntfsd as: xxxxx@storagecraft.com
To unsubscribe send a blank email to %%email.unsub%%

You have to return SMPR in your completion handler and re-complete the IRP
in your dispatch routine after the wait completes. As structured your worker
thread is racing with the IRP completion (and losing on a regular basis.) So
you must defer IRP completion, there is no other solution, and the only way
to do that is to stop completion in your completion handler by returning
SMPR. Once you stop completion you ‘own the IRP’ and thus your concern about
the appropriateness of completing it is misplaced.

Mark Roddy
Consultant
Hollis Technology Solutions
xxxxx@hollistech.com
www.hollistech.com

603-321-1032
wrote in message news:xxxxx@ntfsd…
>
> I have a completion routine that needs to be run at Irql Passive. To
> handle those cases where the Irql is higher I pass off the processing to a
> worker thread. Having read in OSR’s Win2K/XP IFS FAQ that you shouldn’t
> wait in completion for worker to finish (couldn’t figure out how anyway
> since at least one call to set up and wait required an “Irql must be
> passive” function in every scenario I could come up with.) I rewrote my
> Dispatch routine to wait instead.
>
> Problem is sometimes I’m getting a KMODE_EXCEPTION -
> STATUS_ACCESS_VIOLATION when touching Irp stuff which leads me to believe
> that sometimes the Irp has been torn down before my worker thread gets to
> it. Not good.
>
> Am thinking the status I return in the completion routine might be problem
> but don’t think STATUS_MORE_PROCESSING_REQUIRED is appropriate here since,
> among other things, I didn’t create the Irp and therefore wouldn’t feel
> comfortable Completing it.
>
> Here’s a rough sketch of what I’m doing. Any insights would be much
> appreciated:
>
> DISPATCH:
>
> IoCopyCurrentIrpStackLocationToNext(Irp);
>
> pEvent = ExAllocatePool( NonPagedPool, sizeof(KEVENT));
>
> if (pEvent)
> {
> KeInitializeEvent(pEvent, SynchronizationEvent, FALSE);
> IoSetCompletionRoutine(
> Irp,
> CreateCompletion,
> pEvent, //context
> TRUE,
> TRUE,
> TRUE);
>
> (void) IoCallDriver(pDeviceExtension->NextDeviceObject, Irp);
> KeWaitForSingleObject(pEvent, Executive, KernelMode, TRUE, 0);
> ExFreePool(pEvent);
> return Irp->IoStatus.Status;
> }
>
> COMPLETION:
>
> pWData = ExAllocatePool( NonPagedPool, sizeof(WORK_DATA));
> if (pWData)
> {
> pIOWorkItem = IoAllocateWorkItem( DeviceObject );
> pWData->DeviceObject = DeviceObject;
> pWData->Irp = Irp;
> pWData->pIOWorkItem = pIOWorkItem;
> pWData->pIrpStack = pIrpStack;
> pWData->pEvent = Context;
> IoQueueWorkItem( pIOWorkItem, &WorkerCreateFilter, CriticalWorkQueue,
> (PVOID) pWData);
> }
> }
>
> if (Irp->PendingReturned)
> {
> IoMarkIrpPending( Irp );
> }
>
> return STATUS_SUCCESS;
>
> WORKER:
> //Do processing, then… (problem (sometimes): KMODE_EXCEPTION -
> STATUS_ACCESS_VIOLATION Irp already torn down?)
>
> KeSetEvent(pWData->pEvent, 0 , FALSE);
> IoFreeWorkItem(pWData->pIOWorkItem);
> ExFreePool(pWData);
>
>