Help (completion)

I can’t figure out why this is making the computer crash. I’m
trying to spy on data sent from a usb joystick. It’s a lower
filter to hidusb.sys.

This is a section from an internal ioctl routine.

case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
{
KEVENT event ;

DbgPrint(“URB Function:
URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER\n”) ;
KeInitializeEvent(&event, NotificationEvent, FALSE) ;
IoCopyCurrentIrpStackLocationToNext(Irp) ;
IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE)Complete,
&event, TRUE, TRUE, TRUE) ;
status = IoCallDriver(devExt->TopOfStack, Irp) ;
if (status == STATUS_PENDING)
{
DbgPrint(“Waiting for completion\n”) ;
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE,
NULL) ;
DbgPrint(“Waiting Over\n”) ;
} ;

// Irp->IoStatus.Status = status ;
// Irp->IoStatus.Information = 0 ;

IoCompleteRequest(Irp, IO_NO_INCREMENT) ;
return Irp->IoStatus.Status ;
} ;

If I just pass it through the filter driver is fine. But with
this one section of code active the driver gives these results:

URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
Waiting for completion
JoyFilter-> *Complete*
Waiting Over

URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
Waiting for completion
JoyFilter-> *Complete*
Waiting Over

URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
Waiting for completion
JoyFilter-> *Complete*
Waiting Over

URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
Waiting for completion
Waiting Over

URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
Waiting for completion
JoyFilter-> *Complete*
JoyFilter-> *Complete*
Waiting Over

URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
Waiting for completion
JoyFilter-> *Complete*
Waiting Over

URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
Waiting for completion
Waiting Over

URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
Waiting for completion
JoyFilter-> *Complete*
JoyFilter-> *Complete*
Waiting Over

URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
Waiting for completion
Waiting Over

URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
Waiting for completion
JoyFilter-> *Complete*
JoyFilter-> *Complete*
Waiting Over

URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
Waiting for completion
JoyFilter-> *Complete*
Waiting Over

// Sixteen idential to the one above

URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
Waiting for completion
JoyFilter-> *Complete*
Waiting Over

Then the system seems to freeze but in a wierd way.
The mouse still moves and the system appears to be
ok but when you try to click on anything it doesn’t
give any results and then a few seconds later it
blue screens.

Can anyone offer any suggestions?

Hi Chris,

Just a thought,

Who’s thread is possibly waiting on “KeWaitForSingleObject(&event,
Executive, KernelMode, FALSE,
NULL) ;” ? Is it arbitrary?

Rod.

-----Original Message-----
From: Chris Telting [mailto:xxxxx@mindspring.com]
Sent: Thursday, 19 October 2000 6:30 pm
To: NT Developers Interest List
Subject: [ntdev] Help (completion)

I can’t figure out why this is making the computer crash. I’m
trying to spy on data sent from a usb joystick. It’s a lower
filter to hidusb.sys.

This is a section from an internal ioctl routine.

case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
{
KEVENT event ;

DbgPrint(“URB Function:
URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER\n”) ;
KeInitializeEvent(&event, NotificationEvent, FALSE) ;
IoCopyCurrentIrpStackLocationToNext(Irp) ;
IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE)Complete,
&event, TRUE, TRUE, TRUE) ;
status = IoCallDriver(devExt->TopOfStack, Irp) ;
if (status == STATUS_PENDING)
{
DbgPrint(“Waiting for completion\n”) ;
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE,
NULL) ;
DbgPrint(“Waiting Over\n”) ;
} ;

// Irp->IoStatus.Status = status ;
// Irp->IoStatus.Information = 0 ;

IoCompleteRequest(Irp, IO_NO_INCREMENT) ;
return Irp->IoStatus.Status ;
} ;

If I just pass it through the filter driver is fine. But with
this one section of code active the driver gives these results:

URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
Waiting for completion
JoyFilter-> *Complete*
Waiting Over

URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
Waiting for completion
JoyFilter-> *Complete*
Waiting Over

URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
Waiting for completion
JoyFilter-> *Complete*
Waiting Over

URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
Waiting for completion
Waiting Over

URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
Waiting for completion
JoyFilter-> *Complete*
JoyFilter-> *Complete*
Waiting Over

URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
Waiting for completion
JoyFilter-> *Complete*
Waiting Over

URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
Waiting for completion
Waiting Over

URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
Waiting for completion
JoyFilter-> *Complete*
JoyFilter-> *Complete*
Waiting Over

URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
Waiting for completion
Waiting Over

URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
Waiting for completion
JoyFilter-> *Complete*
JoyFilter-> *Complete*
Waiting Over

URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
Waiting for completion
JoyFilter-> *Complete*
Waiting Over

// Sixteen idential to the one above

URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
Waiting for completion
JoyFilter-> *Complete*
Waiting Over

Then the system seems to freeze but in a wierd way.
The mouse still moves and the system appears to be
ok but when you try to click on anything it doesn’t
give any results and then a few seconds later it
blue screens.

Can anyone offer any suggestions?


You are currently subscribed to ntdev as: xxxxx@mobilesoft.com.au
To unsubscribe send a blank email to $subst(‘Email.Unsub’)

There are several problems I see with the code. I would include an assert
that the IRQL == PASSIVE_LEVEL before attempting to initialize the event.
Are you certain of the thread context in which this function is called? Now
for the big problem:

You cannot refer to the Irp after you call IoCompleteRequest() and you are
doing so in the return statement. By the time IoCompleteRequest() returns
the Irp may belong to another process, driver, or whatever. In fact, I have
had this happen to me many times. In a long code sequence it is easy to
forget that and it catches me from time to time. What are you doing in the
completion routine? It must return STATUS_MORE_PROCESSING_REQUIRED to stop
the IO completion process. If you don’t, the IoManager will complete the
Irp or send it to the next higher completion routine.

----- Original Message -----
From: “Chris Telting”
To: “NT Developers Interest List”
Sent: Thursday, October 19, 2000 3:30 AM
Subject: [ntdev] Help (completion)

> I can’t figure out why this is making the computer crash. I’m
> trying to spy on data sent from a usb joystick. It’s a lower
> filter to hidusb.sys.
>
> This is a section from an internal ioctl routine.
>
> > case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
> > {
> > KEVENT event ;
> >
> > DbgPrint(“URB Function:
> URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER\n”) ;
> > KeInitializeEvent(&event, NotificationEvent, FALSE) ;
> > IoCopyCurrentIrpStackLocationToNext(Irp) ;
> > IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE)Complete,
> &event, TRUE, TRUE, TRUE) ;
> > status = IoCallDriver(devExt->TopOfStack, Irp) ;
> > if (status == STATUS_PENDING)
> > {
> > DbgPrint(“Waiting for completion\n”) ;
> > KeWaitForSingleObject(&event, Executive, KernelMode, FALSE,
> NULL) ;
> > DbgPrint(“Waiting Over\n”) ;
> > } ;
> >
> > // Irp->IoStatus.Status = status ;
> > // Irp->IoStatus.Information = 0 ;
> >
> > IoCompleteRequest(Irp, IO_NO_INCREMENT) ;
> > return Irp->IoStatus.Status ;
> > } ;
>
> If I just pass it through the filter driver is fine. But with
> this one section of code active the driver gives these results:
>
> URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
> Waiting for completion
> JoyFilter-> Complete
> Waiting Over
>
> URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
> Waiting for completion
> JoyFilter-> Complete
> Waiting Over
>
> URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
> Waiting for completion
> JoyFilter-> Complete
> Waiting Over
>
> URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
> Waiting for completion
> Waiting Over
>
> URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
> Waiting for completion
> JoyFilter-> Complete
> JoyFilter-> Complete
> Waiting Over
>
> URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
> Waiting for completion
> JoyFilter-> Complete
> Waiting Over
>
> URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
> Waiting for completion
> Waiting Over
>
> URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
> Waiting for completion
> JoyFilter-> Complete
> JoyFilter-> Complete
> Waiting Over
>
> URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
> Waiting for completion
> Waiting Over
>
> URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
> Waiting for completion
> JoyFilter-> Complete
> JoyFilter-> Complete
> Waiting Over
>
> URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
> Waiting for completion
> JoyFilter-> Complete
> Waiting Over
>
> // Sixteen idential to the one above
>
> URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
> Waiting for completion
> JoyFilter-> Complete
> Waiting Over
>
> Then the system seems to freeze but in a wierd way.
> The mouse still moves and the system appears to be
> ok but when you try to click on anything it doesn’t
> give any results and then a few seconds later it
> blue screens.
>
> Can anyone offer any suggestions?
>
>
> —
> You are currently subscribed to ntdev as: xxxxx@mindspring.com
> To unsubscribe send a blank email to $subst(‘Email.Unsub’)
>

> There are several problems I see with the code. I would

include an assert
that the IRQL == PASSIVE_LEVEL before attempting to
initialize the event.
Are you certain of the thread context in which this
function is called? Now
for the big problem:

Yes as you can see from the debug output below
every function was called at passive level. And
I’m not trying to do anything that should make a
difference what IRQL it is. I’m just printing
DbgPrint Messages and then trying to set up a
completion routine. I don’t even try to access
the returned data.

You cannot refer to the Irp after you call
IoCompleteRequest() and you are
doing so in the return statement. By the time
IoCompleteRequest() returns
the Irp may belong to another process, driver, or whatever.
In fact, I have
had this happen to me many times. In a long code sequence
it is easy to
forget that and it catches me from time to time.

I was and am setting an event and then returning
STATUS_MORE_PROCESSING_REQUIRED. Since it did both
of those it can now operate on the IRQ once the
main dispatch routine comes out of it’s wait.

What are you doing in the
completion routine? It must return
STATUS_MORE_PROCESSING_REQUIRED to stop
the IO completion process. If you don’t, the IoManager
will complete the
Irp or send it to the next higher completion routine.

Escuse me I forgot to include the completion routine itself
which is completely dum. I’ve changed the code some so
take another look. Let’s try again:

> case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
> {
> KIRQL Irql ;
> KEVENT event ;
>
> DbgPrint(“URB Function:
URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER\n”) ;
>
> Irql = KeGetCurrentIrql() ;
> if (Irql == PASSIVE_LEVEL)
> DbgPrint(“IRQL: PASSIVE_LEVEL (%u)\n”, Irql) ;
> else if (Irql == APC_LEVEL)
> DbgPrint(“IRQL: APC_LEVEL (%u)\n”, Irql) ;
> else if (Irql == DISPATCH_LEVEL)
> DbgPrint(“IRQL: DISPATCH_LEVEL (%u)\n”, Irql) ;
> else DbgPrint(“IRQL: %u\n”, Irql) ;
>
> KeInitializeEvent(&event, NotificationEvent, FALSE) ;
> IoCopyCurrentIrpStackLocationToNext(Irp) ;
> IoSetCompletionRoutine(Irp,
(PIO_COMPLETION_ROUTINE)InterruptTrandferComplete, &event, TRUE, TRUE,
TRUE) ;
> status = IoCallDriver(devExt->NextDevice, Irp) ;
> KeWaitForSingleObject(&event, Executive, KernelMode, FALSE,
NULL) ;
> DbgPrint(“Continue and Complete\n”) ;
>
> if (Irp->PendingReturned)
> DbgPrint(“PendingReturned\n”) ;
>
> if (status == STATUS_PENDING)
> DbgPrint(“Status: STATUS_PENDING\n”, status) ;
> else DbgPrint(“Status: %x\n”, status) ;
>
> IoCompleteRequest(Irp, IO_NO_INCREMENT) ;
>
> return status ;
> } ;

> NTSTATUS InterruptTrandferComplete(PDEVICE_OBJECT DeviceObject,
PIRP Irp, PVOID Data)
> {
> PKEVENT event ;
>
> DbgPrint(“InterruptTrandferComplete\n”) ;
>
> event = (PKEVENT)Data ;
>
> KeSetEvent(event, 0, FALSE) ;
>
> if (NT_SUCCESS(Irp->IoStatus.Status))
> {
> DbgPrint(“Transfer Success\n”) ;
> }
> else
> {
> DbgPrint(“Transfer Error\n”) ;
> } ;
>
> return STATUS_MORE_PROCESSING_REQUIRED ;
> } ;

Result: 28 copies of the following:

URB Function: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
IRQL: PASSIVE_LEVEL (0)
InterruptTrandferComplete
Transfer Success
Continue and Complete
PendingReturned
Status: STATUS_PENDING

Then the system freezes. This last time it left the mouse
still moving and didn’t outright blue screen but the system
was essentially frozen.

Could I somehow not be returning the IRQ’s to the IO Manager
and hence it is running out of IRQ’s?

And I’ll take the time to spell of my understanding of completion
so you can correct me.

An irq is passed down the stack with IoCallDriver. The return
value from IoCallDriver is the value returned by the lower driver
Iocontrol handler.

You set a completion routine with the IoSetCompletionRoutine
macho to inspect the resulting Irq after it has been “completed”
by a driver calling IoCompleteRequest. All of the completion
routines in the stack are called one after the other from bottom
to top UNLESS the completion routine returns
STATUS_MORE_PROCESSING_REQUIRED in which case the driver stops
processing the IRQ. Which means that it doesn’t call any possible
completetion routines above you. Hence because you returned
STATUS_MORE_PROCESSING_REQUIRED you must call IoCompleteRequest
to start completion going again.

It is the usual case that you signal an event in the completion
before returning STATUS_MORE_PROCESSING_REQUIRED so that you can
continue processing the IRQ in either your iocontrol function or
another thread you have waiting.

I’m not really sure about the PeningReturned flag. I barely
understand it. But I think I tried calling IoMarkIrpPending
in the completion routine and after I get out of the wait
and it doesn’t seem to make any difference. I don’t think
it’s an APC call and if I understand correctly then then it
shouldn’t have an effect. Am I correct in that this flag
is information for the highest driver and tells it to return
STATUS_PENDING?

I think what is happening is that I’m running the IRQ pool
dry. Somehow I might be preventing the IO Manager from
recycling the IRQ’s. Each function completes properly.
There are no freezes in between. It would also seem to
me the reason why the system would freeze and then after
a delay blue screen. Or if the mouse was still functioning
it would blue screen after movement and clicking.

Again thanks for any info.