Problem with PsCreateSystemThread

I use the following code to create a system thread to process items that I
have queued myself. The problem is that the system grinds to a halt when
this thread is running (Windows XP). The mouse cursor does not even move
across the screen! The thread itself seems to be running just fine. I
never get any debug messages about the exception (of course if might not be
able to flush that data out!) This is my first attempt at system threads
and I can’t seem to figure out just what I am doing wrong.

I don’t use the built in work items because this driver must run on NT4
through XP. The implementation changed completely between NT4 and Windows
2000, so I decided to roll my own work item queuing.

Thanks in advance,

Jon

typedef struct _WORKER_THREAD_CONTEXT
{
PKQUEUE WorkQueue; // The queue from which the
// worker thread pulls items.
PKEVENT ShutdownEvent; // Event that when signaled indicates
// that the thread should terminate.

} WORKER_THREAD_CONTEXT, *PWORKER_THREAD_CONTEXT;

typedef struct _MY_DEVICE_EXTENSION
{
// … other members…

PETHREAD WorkerThreadObject;
KQUEUE WorkerQueue;
KEVENT ShutdownEvent;

// … other members…

} MY_DEVICE_EXTENSION, *PMY_DEVICE_EXTENSION;

{
// code from DriverEntry…

//
// This event is used to tell any threads that
// we create that it is time to shutdown.
//
KeInitializeEvent(&devExt->ShutdownEvent,
NotificationEvent,
FALSE);

workerContext = ExAllocatePoolWithTag(NonPagedPool,
sizeof(WORKER_THREAD_CONTEXT),
MY_TAG);

if (NULL != workerContext)
{
workerContext->ShutdownEvent = &devExt->ShutdownEvent;
workerContext->WorkQueue = &devExt->WorkQueue;

status = PsCreateSystemThread(&hThread,
(ACCESS_MASK)0L,
NULL,
0,
NULL,
WorkerThread,
workerContext);

ObReferenceObjectByHandle(hThread,
THREAD_ALL_ACCESS,
NULL,
KernelMode,
&devExt->WorkerThreadObject,
NULL);

ZwClose(hThread);
}

} // code from DriverEntry…

VOID WorkerThread(IN PVOID Context)
{
NTSTATUS status;
WORKER_THREAD_CONTEXT context;
LARGE_INTEGER waitPeriod;
PLIST_ENTRY NodePtr = NULL;

ASSERT(NULL != Context);

context.ShutdownEvent = ((PWORKER_THREAD_CONTEXT)Context)->ShutdownEvent;
context.WorkQueue = ((PWORKER_THREAD_CONTEXT)Context)->WorkQueue;

ExFreePool(Context);

KeSetPriorityThread(KeGetCurrentThread(),
LOW_REALTIME_PRIORITY);

while (TRUE)
{
//
// Test the shutdown event.
//
waitPeriod.QuadPart = 0;

status = KeWaitForSingleObject(context.ShutdownEvent,
Executive,
KernelMode,
FALSE,
&waitPeriod);

if (STATUS_SUCCESS == status)
{
//
// The shutdown event has bee signaled.
//
break;
}

__try
{
waitPeriod.QuadPart = 50000; // =~ 5 milliSeconds

//
// Dequeue an item and process it.
//
NodePtr = KeRemoveQueue(context.WorkQueue,
KernelMode,
&waitPeriod);

if (STATUS_TIMEOUT != (NTSTATUS)NodePtr &&
STATUS_USER_APC != (NTSTATUS)NodePtr)
{
//
// Process the request.
//
_QueueFunc funcPtr = FUNC_PTR_FROM_NODE(NodePtr);

funcPtr(NodePtr);
}
else
{
KeDelayExecutionThread(KernelMode,
FALSE,
&waitPeriod);
}
}

__except(EXCEPTION_EXECUTE_HANDLER)
{
KdPrint((“\n\t!!! Exception in worker thread, 0x%08X\n”,
GetExceptionCode()));
}
}

PsTerminateSystemThread(status);

} // WorkerThread()

Shouldn’t the wait time be negative (relative,) rather than positive
(absolute)?

-----Original Message-----
From: Jon Anglin [mailto:xxxxx@fortres.com]
Sent: Tuesday, June 18, 2002 4:26 PM
To: NT Developers Interest List
Subject: [ntdev] Problem with PsCreateSystemThread

I use the following code to create a system thread to process
items that I have queued myself. The problem is that the
system grinds to a halt when this thread is running (Windows
XP). The mouse cursor does not even move across the screen!
The thread itself seems to be running just fine. I never get
any debug messages about the exception (of course if might
not be able to flush that data out!) This is my first
attempt at system threads and I can’t seem to figure out just
what I am doing wrong.

I don’t use the built in work items because this driver must
run on NT4 through XP. The implementation changed completely
between NT4 and Windows 2000, so I decided to roll my own
work item queuing.

Thanks in advance,

Jon

typedef struct _WORKER_THREAD_CONTEXT
{
PKQUEUE WorkQueue; // The queue from which the
// worker thread pulls items.
PKEVENT ShutdownEvent; // Event that when signaled indicates
// that the thread should terminate.

} WORKER_THREAD_CONTEXT, *PWORKER_THREAD_CONTEXT;

typedef struct _MY_DEVICE_EXTENSION
{
// … other members…

PETHREAD WorkerThreadObject;
KQUEUE WorkerQueue;
KEVENT ShutdownEvent;

// … other members…

} MY_DEVICE_EXTENSION, *PMY_DEVICE_EXTENSION;

{
// code from DriverEntry…

//
// This event is used to tell any threads that
// we create that it is time to shutdown.
//
KeInitializeEvent(&devExt->ShutdownEvent,
NotificationEvent,
FALSE);

workerContext = ExAllocatePoolWithTag(NonPagedPool,
sizeof(WORKER_THREAD_CONTEXT),
MY_TAG);

if (NULL != workerContext)
{
workerContext->ShutdownEvent = &devExt->ShutdownEvent;
workerContext->WorkQueue = &devExt->WorkQueue;

status = PsCreateSystemThread(&hThread,
(ACCESS_MASK)0L,
NULL,
0,
NULL,
WorkerThread,
workerContext);

ObReferenceObjectByHandle(hThread,
THREAD_ALL_ACCESS,
NULL,
KernelMode,
&devExt->WorkerThreadObject,
NULL);

ZwClose(hThread);
}

} // code from DriverEntry…

VOID WorkerThread(IN PVOID Context)
{
NTSTATUS status;
WORKER_THREAD_CONTEXT context;
LARGE_INTEGER waitPeriod;
PLIST_ENTRY NodePtr = NULL;

ASSERT(NULL != Context);

context.ShutdownEvent =
((PWORKER_THREAD_CONTEXT)Context)->ShutdownEvent;
context.WorkQueue =
((PWORKER_THREAD_CONTEXT)Context)->WorkQueue;

ExFreePool(Context);

KeSetPriorityThread(KeGetCurrentThread(),
LOW_REALTIME_PRIORITY);

while (TRUE)
{
//
// Test the shutdown event.
//
waitPeriod.QuadPart = 0;

status = KeWaitForSingleObject(context.ShutdownEvent,
Executive,
KernelMode,
FALSE,
&waitPeriod);

if (STATUS_SUCCESS == status)
{
//
// The shutdown event has bee signaled.
//
break;
}

__try
{
waitPeriod.QuadPart = 50000; // =~ 5 milliSeconds

//
// Dequeue an item and process it.
//
NodePtr = KeRemoveQueue(context.WorkQueue,
KernelMode,
&waitPeriod);

if (STATUS_TIMEOUT != (NTSTATUS)NodePtr &&
STATUS_USER_APC != (NTSTATUS)NodePtr)
{
//
// Process the request.
//
_QueueFunc funcPtr = FUNC_PTR_FROM_NODE(NodePtr);

funcPtr(NodePtr);
}
else
{
KeDelayExecutionThread(KernelMode,
FALSE,
&waitPeriod);
}
}

__except(EXCEPTION_EXECUTE_HANDLER)
{
KdPrint((“\n\t!!! Exception in worker thread,
0x%08X\n”, GetExceptionCode()));
}
}

PsTerminateSystemThread(status);

} // WorkerThread()


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

Look at the OSR web site for a NT Insider article on the use of worker
threads and private queues. I have implemented that code without any
problems. I used a global flag to indicate that the worker thread should
terminate. I don’t see any need for the PsTerminateSystemThread() call
since just falling to a return will kill the system thread. You can do a
wait on an item to be inserted in the queue and wake up every few
milliseconds. Then you can test for the terminate request. Then look at
the queue to see if an item is present. Keep looping up to the wait until
an item is queued. Mark is correct in that the wait must be a negative
number.

You can create multiple threads to work on queue items if they can be
concurrently processed.

----- Original Message -----
From: “Jon Anglin”
Newsgroups: ntdev
To: “NT Developers Interest List”
Sent: Tuesday, June 18, 2002 4:26 PM
Subject: [ntdev] Problem with PsCreateSystemThread

> I use the following code to create a system thread to process items that I
> have queued myself. The problem is that the system grinds to a halt when
> this thread is running (Windows XP). The mouse cursor does not even move
> across the screen! The thread itself seems to be running just fine. I
> never get any debug messages about the exception (of course if might not
be
> able to flush that data out!) This is my first attempt at system threads
> and I can’t seem to figure out just what I am doing wrong.
>
> I don’t use the built in work items because this driver must run on NT4
> through XP. The implementation changed completely between NT4 and Windows
> 2000, so I decided to roll my own work item queuing.
>
> Thanks in advance,
>
> Jon
>
> typedef struct _WORKER_THREAD_CONTEXT
> {
> PKQUEUE WorkQueue; // The queue from which the
> // worker thread pulls items.
> PKEVENT ShutdownEvent; // Event that when signaled indicates
> // that the thread should terminate.
>
> } WORKER_THREAD_CONTEXT, *PWORKER_THREAD_CONTEXT;
>
>
>
> typedef struct _MY_DEVICE_EXTENSION
> {
> // … other members…
>
> PETHREAD WorkerThreadObject;
> KQUEUE WorkerQueue;
> KEVENT ShutdownEvent;
>
> // … other members…
>
> } MY_DEVICE_EXTENSION, *PMY_DEVICE_EXTENSION;
>
>
>
> {
> // code from DriverEntry…
>
> //
> // This event is used to tell any threads that
> // we create that it is time to shutdown.
> //
> KeInitializeEvent(&devExt->ShutdownEvent,
> NotificationEvent,
> FALSE);
>
> workerContext = ExAllocatePoolWithTag(NonPagedPool,
> sizeof(WORKER_THREAD_CONTEXT),
> MY_TAG);
>
> if (NULL != workerContext)
> {
> workerContext->ShutdownEvent = &devExt->ShutdownEvent;
> workerContext->WorkQueue = &devExt->WorkQueue;
>
> status = PsCreateSystemThread(&hThread,
> (ACCESS_MASK)0L,
> NULL,
> 0,
> NULL,
> WorkerThread,
> workerContext);
>
> ObReferenceObjectByHandle(hThread,
> THREAD_ALL_ACCESS,
> NULL,
> KernelMode,
> &devExt->WorkerThreadObject,
> NULL);
>
> ZwClose(hThread);
> }
>
> } // code from DriverEntry…
>
> VOID WorkerThread(IN PVOID Context)
> {
> NTSTATUS status;
> WORKER_THREAD_CONTEXT context;
> LARGE_INTEGER waitPeriod;
> PLIST_ENTRY NodePtr = NULL;
>
> ASSERT(NULL != Context);
>
>
> context.ShutdownEvent =
((PWORKER_THREAD_CONTEXT)Context)->ShutdownEvent;
> context.WorkQueue = ((PWORKER_THREAD_CONTEXT)Context)->WorkQueue;
>
> ExFreePool(Context);
>
> KeSetPriorityThread(KeGetCurrentThread(),
> LOW_REALTIME_PRIORITY);
>
> while (TRUE)
> {
> //
> // Test the shutdown event.
> //
> waitPeriod.QuadPart = 0;
>
> status = KeWaitForSingleObject(context.ShutdownEvent,
> Executive,
> KernelMode,
> FALSE,
> &waitPeriod);
>
> if (STATUS_SUCCESS == status)
> {
> //
> // The shutdown event has bee signaled.
> //
> break;
> }
>
> __try
> {
> waitPeriod.QuadPart = 50000; // =~ 5 milliSeconds
>
> //
> // Dequeue an item and process it.
> //
> NodePtr = KeRemoveQueue(context.WorkQueue,
> KernelMode,
> &waitPeriod);
>
> if (STATUS_TIMEOUT != (NTSTATUS)NodePtr &&
> STATUS_USER_APC != (NTSTATUS)NodePtr)
> {
> //
> // Process the request.
> //
> _QueueFunc funcPtr = FUNC_PTR_FROM_NODE(NodePtr);
>
> funcPtr(NodePtr);
> }
> else
> {
> KeDelayExecutionThread(KernelMode,
> FALSE,
> &waitPeriod);
> }
> }
>
>__except(EXCEPTION_EXECUTE_HANDLER)
> {
> KdPrint((“\n\t!!! Exception in worker thread, 0x%08X\n”,
> GetExceptionCode()));
> }
> }
>
> PsTerminateSystemThread(status);
>
> } // WorkerThread()
>
>
>
>
>
>
>
>
>
> —
> You are currently subscribed to ntdev as: xxxxx@yoshimuni.com
> To unsubscribe send a blank email to %%email.unsub%%

** Reply to message from “David J. Craig” on Wed, 19
Jun 2002 13:16:28 -0400

> I don’t see any need for the PsTerminateSystemThread() call
> since just falling to a return will kill the system thread.

I’d agree that it should work that way, and perhaps it does, but the DDK docs
do explicitly callout for PsTerminateSystemThread() to be used:

From PsCreateSystemThread:
“If the input ProcessHandle is NULL, the created thread is associated with the
system process. Such a thread continues running until either the system is shut
down or the thread terminates itself by calling PsTerminateSystemThread.”

I’d stick with making the call just to be safe. It’s pretty simple and
painless anyway. I’m working on code right now in a driver dealing with two
worker threads, so I might goof with this just out of curiousity.

Sincerely,

Chris Myers
Senior Project Engineer
Quatech, Inc.