Worker Thread and KMDF

I posted the same question a week ago but used a “wrong” sample (DiskFile). Here is my second attempt using the RamDisk Sample. The worker thread code is based on the code in the “input\vserial” sample.

In EvtDeviceAdd:

  • Create a manual Queue.
  • Init a semaphore.
  • Create worker thread.

In EvtIoWrite:

  • Forward the Request to the manual Queue.
  • Release the semaphore.

In the Thread Routine:

  • Wait on the semaphore.
  • Retrieve a Request from the manual Queue, process, and complete.

The code seems to work fine. But if EvtDeviceAdd fails to complete for some reasons (for example, couldn’t alloc memory for the RamDisk), the system crashes.

Below is some trace data:

*********************************************
* Windows Ramdisk Driver - Driver Framework Edition.
*********************************************
Built Nov 19 2008 11:59:29
***TEST*** RamDisk Enter DeviceAdd
DiskSize = 0x12800000 (to force a failed alloc)
RootDirEntries = 0x200
SectorsPerCluster = 0x2
DriveLetter = R:
***TEST*** RamDisk Exit DeviceAdd. Failed NonPagePool alloc: 0x00000000
***TEST*** RamDisk Enter ContextCleanup
(Released semaphore here. Thread Routine should wake up and terminate itself. But it didn’t)
***TEST*** RamDisk Dereference thread obj
***TEST*** RamDisk Exit ContextCleanup

*** Fatal System Error: 0x000000ce
(0xF44BD0D0,0x00000000,0xF44BD0D0,0x00000000)

kd> !analyze -v
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************

DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS (ce)

My questions are:

  • Is this an acceptable way to do worker thread in DMDF?
  • Why ContextCleanup called if the driver has not been loaded?
  • Why the Context Cleanup code doesn’t terminate the thread? Below is the subroutine:

VOID RamDiskEvtDeviceContextCleanup(IN WDFDEVICE Device)
{
PDEVICE_EXTENSION pDeviceExtension = DeviceGetExtension(Device);

PAGED_CODE();

KdPrint((__DRIVER_NAME " Enter ContextCleanup\n"));

// Set flag to terminate thread
pDeviceExtension->bTerminateThread = TRUE;

// Make sure the thread wakes up
KeReleaseSemaphore(&pDeviceExtension->IrpQueueSem,
0, // No priority boost
1, // Increment semaphore by 1
TRUE); // WaitForXxx after this call

// Wait for the thread to terminate
KeWaitForSingleObject(&pDeviceExtension->pThreadObj,
Executive,
KernelMode,
FALSE,
NULL);

KdPrint((__DRIVER_NAME " Dereference thread obj\n"));
ObDereferenceObject(&pDeviceExtension->pThreadObj);

if(pDeviceExtension->DiskImage)
{
ExFreePool(pDeviceExtension->DiskImage);
}
KdPrint((__DRIVER_NAME " Exit ContextCleanup\n"));
}

And thread subroutine:

VOID WorkerThreadRoutine(IN PVOID pContext)
{
// Vars declarations.

KdPrint((__DRIVER_NAME " Thread in\n"));

// Sets thread priority
KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);

while(TRUE)
{
// Wake up when there are Requests in the Queue or when thread should be terminated
KeWaitForSingleObject(&pDevExt->IrpQueueSem, Executive, KernelMode, FALSE, NULL);

// Check termination flag
if(pDevExt->bTerminateThread)
{
PsTerminateSystemThread(STATUS_SUCCESS);
KdPrint((__DRIVER_NAME " Thread terminated\n"));
return;
}
// Retrieve a Request from the manual queue and process

}
KdPrint((__DRIVER_NAME " Thread out (never get here)\n"));

return;
}

Thank you for your help.

Chu Bun

I ran into another problem. Sometimes, in the worker thread, it takes a very long time for the write operation WdfMemoryCopyToBuffer(hMemory,0,pRamImg+offset, len) to complete. This often happens during starting up or shutting down.

Are you copying to a pagable buffer? How are you measuring as to know that it is taking longer than normal?

d

Sent from my phone with no t9, all spilling mistakes are not intentional.

-----Original Message-----
From: xxxxx@yahoo.com
Sent: Friday, November 21, 2008 1:15 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Worker Thread and KMDF

I ran into another problem. Sometimes, in the worker thread, it takes a very long time for the write operation WdfMemoryCopyToBuffer(hMemory,0,pRamImg+offset, len) to complete. This often happens during starting up or shutting down.


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

The RamImg is alloc’ed with NonPagePool flag.
Usually, trace messages from the write routines flies by real fast. But once in a while the trace messages halt for minutes before it says the write is done. Should I crease the priority level of the thread?

I found why EvtDeviceAdd crashes the system. By the time EvtDeviceContextCleanup runs, the worker thread has not started yet and PsTerminateSystemThread is never called. Maybe I should create the thread just before exiting EvtDeviceAdd and assume nothing should go wrong between then and the time the thread starts?

No, you should not hope for the best and pray that it works. Instead, add a KEVENT to your device context and init it before you create the thread. The first thing your thread should do is set this event. In you add device routine you then wait on this event after creating the thread. This will guarantee that your thread has started and will simplify your cleanup and give deterministic behavior.

d

Sent from my phone with no t9, all spilling mistakes are not intentional.

-----Original Message-----
From: xxxxx@yahoo.com
Sent: Friday, November 21, 2008 4:08 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Worker Thread and KMDF

I found why EvtDeviceAdd crashes the system. By the time EvtDeviceContextCleanup runs, the worker thread has not started yet and PsTerminateSystemThread is never called. Maybe I should create the thread just before exiting EvtDeviceAdd and assume nothing should go wrong between then and the time the thread starts?


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

Thank you for the tip.