USB Bus Driver Thread Question

Running on an Intel dual core XP SP2 PC.

User application calls DeviceIoControl to send an IOCTL to retrieve some data from the USB device. The data retrieval is done asynchronously, so an IRP/URB is allocated. A completion routine is registered, and then IoCallDriver sends the irp to the USBD. At some point later the completion routine is called by the USBD when it has data to return.

Sometimes in the debug trace I see the same thread that sent the IOCTL at IRQL 0, used by the USBD, in the completion routine, at IRQL 2. At other times the completion routine is called in a different thread at IRQL 2. Using PsGetCurrentThread() to see what thread the code is running in.

Question: Why does the completion routine called by the USB Bus Driver(USBD) run in
the same thread originated in usermode, and at other times in a separate system thread?

Thanks
-decoder

xxxxx@maxlinear.com wrote:

Running on an Intel dual core XP SP2 PC.

User application calls DeviceIoControl to send an IOCTL to retrieve some data from the USB device. The data retrieval is done asynchronously, so an IRP/URB is allocated. A completion routine is registered, and then IoCallDriver sends the irp to the USBD. At some point later the completion routine is called by the USBD when it has data to return.

Sometimes in the debug trace I see the same thread that sent the IOCTL at IRQL 0, used by the USBD, in the completion routine, at IRQL 2. At other times the completion routine is called in a different thread at IRQL 2. Using PsGetCurrentThread() to see what thread the code is running in.

Question: Why does the completion routine called by the USB Bus Driver(USBD) run in
the same thread originated in usermode, and at other times in a separate system thread?

Basically, it runs in whatever thread happened to be running when the
USB host controller fired its interrupt at end of frame.

That’s not technically true, because the host controller driver actually
fires off a DPC to do the completion, but it’s essentially the same
thing. Whatever thread happened to be running is “borrowed” to handle
the completion.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Why does it matter which thread it uses? For instance, let’s say there is a host controller global resource that must be used for the transfer in question. If the resource is free, the calling thread gets it and proceeds. If it is not free, your request is queued and processed when the resource eventually becomes free.

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Tim Roberts
Sent: Friday, June 27, 2008 11:39 AM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] USB Bus Driver Thread Question

xxxxx@maxlinear.com wrote:

Running on an Intel dual core XP SP2 PC.

User application calls DeviceIoControl to send an IOCTL to retrieve some data from the USB device. The data retrieval is done asynchronously, so an IRP/URB is allocated. A completion routine is registered, and then IoCallDriver sends the irp to the USBD. At some point later the completion routine is called by the USBD when it has data to return.

Sometimes in the debug trace I see the same thread that sent the IOCTL at IRQL 0, used by the USBD, in the completion routine, at IRQL 2. At other times the completion routine is called in a different thread at IRQL 2. Using PsGetCurrentThread() to see what thread the code is running in.

Question: Why does the completion routine called by the USB Bus Driver(USBD) run in
the same thread originated in usermode, and at other times in a separate system thread?

Basically, it runs in whatever thread happened to be running when the
USB host controller fired its interrupt at end of frame.

That’s not technically true, because the host controller driver actually
fires off a DPC to do the completion, but it’s essentially the same
thing. Whatever thread happened to be running is “borrowed” to handle
the completion.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.


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

Why does it matter which thread it uses? For instance, let’s say there is a
host controller global resource that must be used for the transfer in question.
If the resource is free, the calling thread gets it and proceeds. If it is not
free, your request is queued and processed when the resource eventually becomes
free.

d

What happens if I have created a thread in my driver using PsCreateSystemThread(), and set the priority to HIGH using KeSetPriorityThread(). Can it also be “borrowed” by the USBD completion routine. Does the notion of whatever thread is running will be used also apply to private worker threads created by my USB driver?

-decoder

decoder wrote:

What happens if I have created a thread in my driver using
PsCreateSystemThread(), and set the priority to HIGH using
KeSetPriorityThread(). Can it also be “borrowed” by the USBD
completion routine. Does the notion of whatever thread is running
will be used also apply to private worker threads created by my
USB driver?

Seriously: why do you care?

> Question: Why does the completion routine called by the USB Bus Driver(USBD)

run in
the same thread originated in usermode, and at other times in a separate
system
thread?

You have no guarantees at all about the thread context in the completion
routine.

Sorry. Design your code in a way in which it will not rely on a thread context
there.


Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

> What happens if I have created a thread in my driver using

PsCreateSystemThread(), and set the priority to HIGH using
KeSetPriorityThread>(). Can it also be “borrowed” by the USBD completion
routine.

Yes it can.

Stop relying on thread context in completion routines. Just imagine that there
is no such thing as “thread” when the completion routine runs.

Same is true for timer DPCs and for your own possible DPCs queued by
KeInsertQueueDpc.

Actually, the completion routine is usually called by IoCompleteRequest in the
lower driver (USB stack for you), and it is usually called from the DPC
inserted by KeInsertQueueDpc in the ISR routine of the bottom-most hardware
driver (USB HC driver).

So, completion routines are usually called in DPC context.

As about DPCs - in Windows, they are not bound to a thread, KeGetCurrentThread
is just nonsense in them.

For instance, the dispatcher can fire a DPC in-between the switch from one
thread to another or such. This is a very low-level implementation detail of
the dispatcher, and the Windows architecture provides no guarantees there.

So, the whole Windows kernel framework just does not support the notion of
“current thread” in DPCs and thus completion routines.


Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com