handling asychronous reads and writes

hi

I have a list of questions below - I hope that somebody with a lot more driver experience than me can help me out. Any other suggestions would be great if you care to offer them.

I am trying to handle asychronous WriteFile() and ReadFile() calls for my Virtual Serial over USB driver. It exposes 4 com ports to application, as you may remember. The app folks set the timeouts associate the reads and writes via a call to SetCommTimeouts().

(1) For the WriteFile() case, the IRPs get put on a cancel safe queue. However, I need to be able to cancel them if they haven’t been processed.
So, is there a way for me to store a tick count in with the IRP somewhere? I would like to store the tick count of when I put the IRP on a queue. I could allocate another stack location and then try to remove it before I submit the IRP, but perhaps that is too messy. I could have a separate data structure to keep track of tick counts for the IRPs on the queue, but hope I don’t have to go there.

(2) I was thinking of having a timer go off every 100 ms to check to see if I have data available to fulfill the read IRPs (I have a separate polling IRP that I keep submitting, that actually asks for data from the device, independent of any ReadFile() calls). Is this a Timer associated with a DPC? Or would I want to use a separate thread or what?

(3) I can maintain a separate queue for every com port. However, it is easier to keep one queue so that I can serialize USB read/write requests sent to the USB bus driver, as I am doing now. With one queue, I need to be able to do a Peek() into the circular buffer and be able to pull IRPs out of there not necessarily from the head of the queue? Is this possible? I need to read up on the cancel-safe queues since I see the Peek callback but it looks like that is for use by the I/O manager and not my driver. Am I allowed to peek and pull IRPs off the queue in my driver provided that I take the lock - or would that screw up the I/O manager? I do not want to maintain my own queue because of the warnings about race conditions I’ve heard about.

Background:
Currently, when an app does a read, the IRP_MJ_READ handler just returns whatever is in my circular buffer for that particular com port. Since it’s a quick operation to do this, I don’t pend the IRP. (But I have to change this because I need to support asychronous operations.) Thus, there really isn’t IRP_MJ_READs that get submitted down to the usb bus driver due to a ReadFile(). Because USB requires the host to poll the target for data, I have a polling IRP that I submit down the bus driver asking for data - I take the returned data and stuff it into a circular buffer (one per each com port). Then I resubmit the IRP from the completion routine (actually via a Work item to get the IRQL level back down to passive).

Thanks in advance.

As long as you “own” an IRP, you also “own” Irp->Tail.Overlay.DriverContext.
This is an array of 4 PVOIDs. You can either store data directly in this
structure (e.g. cast &Irp->Tail.Overlay.DriverContext[0] to a pointer to
your own structure, as long as the sizeof that structure is less than
sizeof(PVOID[4]), or you can allocate a tracking structure, and store a
pointer to it in DriverContext[0…3]. Your driver ceases to own this block
when it either completes the IRP (returning it to the issuer) or passes it
down to another device object.

Be aware that the Cancel-Safe Queue implementation uses DriverContext[3] for
itself, so you can’t use that field. This constraint is mentioned in the
docs for IoCsqInitialize.

– arlie


From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of S. Drasnin
Sent: Friday, October 28, 2005 6:54 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] handling asychronous reads and writes

hi

I have a list of questions below - I hope that somebody with a lot more
driver experience than me can help me out. Any other suggestions would be
great if you care to offer them.

I am trying to handle asychronous WriteFile() and ReadFile() calls for my
Virtual Serial over USB driver. It exposes 4 com ports to application, as
you may remember. The app folks set the timeouts associate the reads and
writes via a call to SetCommTimeouts().

(1) For the WriteFile() case, the IRPs get put on a cancel safe queue.
However, I need to be able to cancel them if they haven’t been processed.
So, is there a way for me to store a tick count in with the IRP somewhere? I
would like to store the tick count of when I put the IRP on a queue. I could
allocate another stack location and then try to remove it before I submit
the IRP, but perhaps that is too messy. I could have a separate data
structure to keep track of tick counts for the IRPs on the queue, but hope I
don’t have to go there.

(2) I was thinking of having a timer go off every 100 ms to check to see if
I have data available to fulfill the read IRPs (I have a separate polling
IRP that I keep submitting, that actually asks for data from the device,
independent of any ReadFile() calls). Is this a Timer associated with a DPC?
Or would I want to use a separate thread or what?

(3) I can maintain a separate queue for every com port. However, it is
easier to keep one queue so that I can serialize USB read/write requests
sent to the USB bus driver, as I am doing now. With one queue, I need to be
able to do a Peek() into the circular buffer and be able to pull IRPs out of
there not necessarily from the head of the queue? Is this possible? I need
to read up on the cancel-safe queues since I see the Peek callback but it
looks like that is for use by the I/O manager and not my driver. Am I
allowed to peek and pull IRPs off the queue in my driver provided that I
take the lock - or would that screw up the I/O manager? I do not want to
maintain my own queue because of the warnings about race conditions I’ve
heard about.

Background:
Currently, when an app does a read, the IRP_MJ_READ handler just returns
whatever is in my circular buffer for that particular com port. Since it’s a
quick operation to do this, I don’t pend the IRP. (But I have to change this
because I need to support asychronous operations.) Thus, there really isn’t
IRP_MJ_READs that get submitted down to the usb bus driver due to a
ReadFile(). Because USB requires the host to poll the target for data, I
have a polling IRP that I submit down the bus driver asking for data - I
take the returned data and stuff it into a circular buffer (one per each com
port). Then I resubmit the IRP from the completion routine (actually via a
Work item to get the IRQL level back down to passive).

Thanks in advance.


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

You are currently subscribed to ntdev as: unknown lmsubst tag argument: ‘’
To unsubscribe send a blank email to xxxxx@lists.osr.com

As for the other questions.

DPCs do not have timers, but timers have DPCs. Look at KeSetTimer(Ex).
There is also a “Timer Objects and DPCs” topic (which is linked off of
the KeInitializeTimerEx topic).

As for iterating over the queue, you can always just pop each request
off the queue, check the time, and if not yet expired, put it back on
the queue. You can also do some optimizations here by sorting the queue
by timeout expiration time. This way you can iterate up to a certain
point in the list w/out needlessly popping off requests which will not
be expired. Also, you can store the current expiration time in your
extension and only return PIRPs which have expired in your
implementation of CsqPeekNextIrp().

d

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Arlie Davis
Sent: Friday, October 28, 2005 4:08 PM
To: Windows System Software Devs Interest List
Subject: RE: [ntdev] handling asychronous reads and writes

As long as you “own” an IRP, you also “own”
Irp->Tail.Overlay.DriverContext.
This is an array of 4 PVOIDs. You can either store data directly in
this
structure (e.g. cast &Irp->Tail.Overlay.DriverContext[0] to a pointer to
your own structure, as long as the sizeof that structure is less than
sizeof(PVOID[4]), or you can allocate a tracking structure, and store a
pointer to it in DriverContext[0…3]. Your driver ceases to own this
block
when it either completes the IRP (returning it to the issuer) or passes
it
down to another device object.

Be aware that the Cancel-Safe Queue implementation uses DriverContext[3]
for
itself, so you can’t use that field. This constraint is mentioned in
the
docs for IoCsqInitialize.

– arlie


From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of S. Drasnin
Sent: Friday, October 28, 2005 6:54 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] handling asychronous reads and writes

hi

I have a list of questions below - I hope that somebody with a lot more
driver experience than me can help me out. Any other suggestions would
be
great if you care to offer them.

I am trying to handle asychronous WriteFile() and ReadFile() calls for
my
Virtual Serial over USB driver. It exposes 4 com ports to application,
as
you may remember. The app folks set the timeouts associate the reads
and
writes via a call to SetCommTimeouts().

(1) For the WriteFile() case, the IRPs get put on a cancel safe queue.
However, I need to be able to cancel them if they haven’t been
processed.
So, is there a way for me to store a tick count in with the IRP
somewhere? I
would like to store the tick count of when I put the IRP on a queue. I
could
allocate another stack location and then try to remove it before I
submit
the IRP, but perhaps that is too messy. I could have a separate data
structure to keep track of tick counts for the IRPs on the queue, but
hope I
don’t have to go there.

(2) I was thinking of having a timer go off every 100 ms to check to see
if
I have data available to fulfill the read IRPs (I have a separate
polling
IRP that I keep submitting, that actually asks for data from the device,
independent of any ReadFile() calls). Is this a Timer associated with a
DPC?
Or would I want to use a separate thread or what?

(3) I can maintain a separate queue for every com port. However, it is
easier to keep one queue so that I can serialize USB read/write requests
sent to the USB bus driver, as I am doing now. With one queue, I need to
be
able to do a Peek() into the circular buffer and be able to pull IRPs
out of
there not necessarily from the head of the queue? Is this possible? I
need
to read up on the cancel-safe queues since I see the Peek callback but
it
looks like that is for use by the I/O manager and not my driver. Am I
allowed to peek and pull IRPs off the queue in my driver provided that I
take the lock - or would that screw up the I/O manager? I do not want
to
maintain my own queue because of the warnings about race conditions I’ve
heard about.

Background:
Currently, when an app does a read, the IRP_MJ_READ handler just returns
whatever is in my circular buffer for that particular com port. Since
it’s a
quick operation to do this, I don’t pend the IRP. (But I have to change
this
because I need to support asychronous operations.) Thus, there really
isn’t
IRP_MJ_READs that get submitted down to the usb bus driver due to a
ReadFile(). Because USB requires the host to poll the target for data,
I
have a polling IRP that I submit down the bus driver asking for data - I
take the returned data and stuff it into a circular buffer (one per each
com
port). Then I resubmit the IRP from the completion routine (actually via
a
Work item to get the IRQL level back down to passive).

Thanks in advance.


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

You are currently subscribed to ntdev as: unknown lmsubst tag argument:
‘’
To unsubscribe send a blank email to xxxxx@lists.osr.com


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

You are currently subscribed to ntdev as: xxxxx@microsoft.com
To unsubscribe send a blank email to xxxxx@lists.osr.com

hi

Thanks Doron and Arlie for the quick/helpful replies back.

The timeout value will be: (time IRP is queued) + timeout specified by the SetCommTimeout() function call. However, since apps can call this function again to change the timeouts, you are right in saying that the queue isn’t necessarily ordered in terms of expiration. I will have to walk the queue if I don’t reorder it. The reason I don’t want to reorder it is because the app code expects that the data for a WriteFile call for com port goes out before a subsequent WriteFile() call for the same com port.

(I assume that if I do a pop and push back on, I can only push back to the tail.)

So, if I instead need to implement a peek function, is it safe to do so as long as I take the lock (the one associated with the lock callback) and release it when I’m done? If I find an IRP that needs to be removed by the queue by my driver because it needs to be completed with an error (due to a timeout: current tick > setcommticktimeout + irp submitted tick count) or without an error (because I can fulfill its request), can I safely do this?

In other words, can I mess around with the cancel safe queue or is the I/O manager only supposed to do that?

thanks very much!

----- Original Message -----
From: Doron Holanmailto:xxxxx
To: Windows System Software Devs Interest Listmailto:xxxxx
Sent: Friday, October 28, 2005 4:23 PM
Subject: RE: [ntdev] handling asychronous reads and writes

As for the other questions.

DPCs do not have timers, but timers have DPCs. Look at KeSetTimer(Ex).
There is also a “Timer Objects and DPCs” topic (which is linked off of
the KeInitializeTimerEx topic).

As for iterating over the queue, you can always just pop each request
off the queue, check the time, and if not yet expired, put it back on
the queue. You can also do some optimizations here by sorting the queue
by timeout expiration time. This way you can iterate up to a certain
point in the list w/out needlessly popping off requests which will not
be expired. Also, you can store the current expiration time in your
extension and only return PIRPs which have expired in your
implementation of CsqPeekNextIrp().

d

-----Original Message-----
From: xxxxx@lists.osr.commailto:xxxxx
[mailto:xxxxx@lists.osr.com] On Behalf Of Arlie Davis
Sent: Friday, October 28, 2005 4:08 PM
To: Windows System Software Devs Interest List
Subject: RE: [ntdev] handling asychronous reads and writes

As long as you “own” an IRP, you also “own”
Irp->Tail.Overlay.DriverContext.
This is an array of 4 PVOIDs. You can either store data directly in
this
structure (e.g. cast &Irp->Tail.Overlay.DriverContext[0] to a pointer to
your own structure, as long as the sizeof that structure is less than
sizeof(PVOID[4]), or you can allocate a tracking structure, and store a
pointer to it in DriverContext[0…3]. Your driver ceases to own this
block
when it either completes the IRP (returning it to the issuer) or passes
it
down to another device object.

Be aware that the Cancel-Safe Queue implementation uses DriverContext[3]
for
itself, so you can’t use that field. This constraint is mentioned in
the
docs for IoCsqInitialize.

– arlie

________________________________

From: xxxxx@lists.osr.commailto:xxxxx
[mailto:xxxxx@lists.osr.com] On Behalf Of S. Drasnin
Sent: Friday, October 28, 2005 6:54 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] handling asychronous reads and writes

hi

I have a list of questions below - I hope that somebody with a lot more
driver experience than me can help me out. Any other suggestions would
be
great if you care to offer them.

I am trying to handle asychronous WriteFile() and ReadFile() calls for
my
Virtual Serial over USB driver. It exposes 4 com ports to application,
as
you may remember. The app folks set the timeouts associate the reads
and
writes via a call to SetCommTimeouts().

(1) For the WriteFile() case, the IRPs get put on a cancel safe queue.
However, I need to be able to cancel them if they haven’t been
processed.
So, is there a way for me to store a tick count in with the IRP
somewhere? I
would like to store the tick count of when I put the IRP on a queue. I
could
allocate another stack location and then try to remove it before I
submit
the IRP, but perhaps that is too messy. I could have a separate data
structure to keep track of tick counts for the IRPs on the queue, but
hope I
don’t have to go there.

(2) I was thinking of having a timer go off every 100 ms to check to see
if
I have data available to fulfill the read IRPs (I have a separate
polling
IRP that I keep submitting, that actually asks for data from the device,
independent of any ReadFile() calls). Is this a Timer associated with a
DPC?
Or would I want to use a separate thread or what?

(3) I can maintain a separate queue for every com port. However, it is
easier to keep one queue so that I can serialize USB read/write requests
sent to the USB bus driver, as I am doing now. With one queue, I need to
be
able to do a Peek() into the circular buffer and be able to pull IRPs
out of
there not necessarily from the head of the queue? Is this possible? I
need
to read up on the cancel-safe queues since I see the Peek callback but
it
looks like that is for use by the I/O manager and not my driver. Am I
allowed to peek and pull IRPs off the queue in my driver provided that I
take the lock - or would that screw up the I/O manager? I do not want
to
maintain my own queue because of the warnings about race conditions I’ve
heard about.

Background:
Currently, when an app does a read, the IRP_MJ_READ handler just returns
whatever is in my circular buffer for that particular com port. Since
it’s a
quick operation to do this, I don’t pend the IRP. (But I have to change
this
because I need to support asychronous operations.) Thus, there really
isn’t
IRP_MJ_READs that get submitted down to the usb bus driver due to a
ReadFile(). Because USB requires the host to poll the target for data,
I
have a polling IRP that I submit down the bus driver asking for data - I
take the returned data and stuff it into a circular buffer (one per each
com
port). Then I resubmit the IRP from the completion routine (actually via
a
Work item to get the IRQL level back down to passive).

Thanks in advance.


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256http:

You are currently subscribed to ntdev as: unknown lmsubst tag argument:
‘’
To unsubscribe send a blank email to xxxxx@lists.osr.commailto:xxxxx


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256http:

You are currently subscribed to ntdev as: xxxxx@microsoft.commailto:xxxxx
To unsubscribe send a blank email to xxxxx@lists.osr.commailto:xxxxx


Questions? First check the Kernel Driver FAQ at http://www.osronline.com/article.cfm?id=256http:

You are currently subscribed to ntdev as: unknown lmsubst tag argument: ‘’
To unsubscribe send a blank email to xxxxx@lists.osr.commailto:xxxxx</mailto:xxxxx></http:></mailto:xxxxx></mailto:xxxxx></http:></mailto:xxxxx></http:></mailto:xxxxx></mailto:xxxxx></mailto:xxxxx></mailto:xxxxx>

The CSQ is your object, not the I/O manager’s. You control insertion and removal into the IOCSQ. The only direct access the io manager has to the CSQ is via the irp’s cancel routine. You can easily acquire the queue lock and walk the list of requests directly. Removal of a request from the queue is another question while you are holding the queue lock b/c the CSQ removal API is not callable while the lock is held.

d


From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of S. Drasnin
Sent: Friday, October 28, 2005 4:51 PM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] handling asychronous reads and writes

hi
?
Thanks Doron and Arlie for the quick/helpful replies back.
?
?
The timeout value will be: (time IRP is queued) + timeout specified by the SetCommTimeout() function call. However, since apps can call this function again to change the timeouts, you are right in saying that the queue isn’t necessarily ordered in terms of expiration.? I will have to walk the queue if I don’t reorder it. The reason I don’t want to reorder it is because the app code expects that the data for a WriteFile call for com port goes out before a subsequent WriteFile() call for the same com port.
?
(I assume that if I do a pop and push back on, I can only push back to the tail.)
?
So, if I instead need to implement a peek function, is it safe to do so as long as I take the lock (the one associated with the lock callback) and release it when I’m done? If I find an IRP that needs to be removed by the queue by my driver because it needs to be completed? with an error (due to a timeout: current tick > setcommticktimeout + irp submitted tick count) or without an error (because I can fulfill its request), can I safely do this?
?
In other words, can I mess around with the cancel safe queue or is the I/O manager only supposed to do that?
?
thanks very much!
?
----- Original Message -----
From: Doron Holan
To: Windows System Software Devs Interest List
Sent: Friday, October 28, 2005 4:23 PM
Subject: RE: [ntdev] handling asychronous reads and writes

As for the other questions.

DPCs do not have timers, but timers have DPCs.? Look at KeSetTimer(Ex).
There is also a “Timer Objects and DPCs” topic (which is linked off of
the KeInitializeTimerEx topic).

As for iterating over the queue, you can always just pop each request
off the queue, check the time, and if not yet expired, put it back on
the queue.? You can also do some optimizations here by sorting the queue
by timeout expiration time.? This way you can iterate up to a certain
point in the list w/out needlessly popping off requests which will not
be expired.? Also, you can store the current expiration time in your
extension and only return PIRPs which have expired in your
implementation of CsqPeekNextIrp().

d

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Arlie Davis
Sent: Friday, October 28, 2005 4:08 PM
To: Windows System Software Devs Interest List
Subject: RE: [ntdev] handling asychronous reads and writes

As long as you “own” an IRP, you also “own”
Irp->Tail.Overlay.DriverContext.
This is an array of 4 PVOIDs.? You can either store data directly in
this
structure (e.g. cast &Irp->Tail.Overlay.DriverContext[0] to a pointer to
your own structure, as long as the sizeof that structure is less than
sizeof(PVOID[4]), or you can allocate a tracking structure, and store a
pointer to it in DriverContext[0…3].? Your driver ceases to own this
block
when it either completes the IRP (returning it to the issuer) or passes
it
down to another device object.
?
Be aware that the Cancel-Safe Queue implementation uses DriverContext[3]
for
itself, so you can’t use that field.? This constraint is mentioned in
the
docs for IoCsqInitialize.
?
– arlie
?


From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of S. Drasnin
Sent: Friday, October 28, 2005 6:54 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] handling asychronous reads and writes

hi
?
I have a list of questions below - I hope that somebody with a lot more
driver experience than me can help me out. Any other suggestions would
be
great if you care to offer them.
?
I am trying to handle asychronous WriteFile() and ReadFile() calls for
my
Virtual Serial over USB driver. It exposes 4 com ports to application,
as
you may remember.? The app folks set the timeouts associate the reads
and
writes via a call to SetCommTimeouts().

(1) For the WriteFile() case, the IRPs get put on a cancel safe queue.
However, I need to be able to cancel them if they haven’t been
processed.
So, is there a way for me to store a tick count in with the IRP
somewhere? I
would like to store the tick count of when I put the IRP on a queue. I
could
allocate another stack location and then try to remove it before I
submit
the IRP, but perhaps that is too messy. I could have a separate data
structure to keep track of tick counts for the IRPs on the queue, but
hope I
don’t have to go there.

(2) I was thinking of having a timer go off every 100 ms to check to see
if
I have data available to fulfill the read IRPs (I have a separate
polling
IRP that I keep submitting, that actually asks for data from the device,
independent of any ReadFile() calls). Is this a Timer associated with a
DPC?
Or would I want to use a separate thread or what?

(3) I can maintain a separate queue for every com port. However, it is
easier to keep one queue so that I can serialize USB read/write requests
sent to the USB bus driver, as I am doing now. With one queue, I need to
be
able to do a Peek() into the circular buffer and be able to pull IRPs
out of
there not necessarily from the head of the queue? Is this possible? I
need
to read up on the cancel-safe queues since I see the Peek callback but
it
looks like that is for use by the I/O manager and not my driver. Am I
allowed to peek and pull IRPs off the queue in my driver provided that I
take the lock - or would that screw up the I/O manager?? I? do not want
to
maintain my own queue because of the warnings about race conditions I’ve
heard about.
?
Background:
Currently, when an app does a read, the IRP_MJ_READ handler just returns
whatever is in my circular buffer for that particular com port. Since
it’s a
quick operation to do this, I don’t pend the IRP. (But I have to change
this
because I need to support asychronous operations.) Thus, there really
isn’t
IRP_MJ_READs that get submitted down to the usb bus driver due to a
ReadFile().? Because USB requires the host to poll the target for data,
I
have a polling IRP that I submit down the bus driver asking for data - I
take the returned data and stuff it into a circular buffer (one per each
com
port). Then I resubmit the IRP from the completion routine (actually via
a
Work item to get the IRQL level back down to passive).?

Thanks in advance.


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

You are currently subscribed to ntdev as: unknown lmsubst tag argument:
‘’
To unsubscribe send a blank email to xxxxx@listsosr.com


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

You are currently subscribed to ntdev as: xxxxx@microsoft.com
To unsubscribe send a blank email to xxxxx@listsosr.com


Questions? First check the Kernel Driver FAQ at http://www.osronline.com/article.cfm?id=256

You are currently subscribed to ntdev as: unknown lmsubst tag argument: ‘’
To unsubscribe send a blank email to xxxxx@listsosr.com


Questions? First check the Kernel Driver FAQ at http://www.osronline.com/article.cfm?id=256

You are currently subscribed to ntdev as: unknown lmsubst tag argument: ‘’
To unsubscribe send a blank email to xxxxx@lists.osr.com

Thanks for the info - and especially for the gotcha about the lock…

So, the problem I’m trying to solve isn’t that unique. There must be other drivers doing this. What approach do people normally take? I could see that they roll their own queues rather than using the using the cancel safe queue.

For now, I’m going to explore Scott’s idea of using a peek context that passes in a criteria for matching (I.e. the number of bytes, the expiration tick value from the SetCommTimeout() call from the application layer…) that is used to determine what IRP (if any) to return.

thanks

----- Original Message -----
From: Doron Holanmailto:xxxxx
To: Windows System Software Devs Interest Listmailto:xxxxx
Sent: Sunday, October 30, 2005 3:29 PM
Subject: RE: [ntdev] handling asychronous reads and writes

The CSQ is your object, not the I/O manager’s. You control insertion and removal into the IOCSQ. The only direct access the io manager has to the CSQ is via the irp’s cancel routine. You can easily acquire the queue lock and walk the list of requests directly. Removal of a request from the queue is another question while you are holding the queue lock b/c the CSQ removal API is not callable while the lock is held.

d

________________________________________
From: xxxxx@lists.osr.commailto:xxxxx [mailto:xxxxx@lists.osr.com] On Behalf Of S. Drasnin
Sent: Friday, October 28, 2005 4:51 PM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] handling asychronous reads and writes

hi

Thanks Doron and Arlie for the quick/helpful replies back.

The timeout value will be: (time IRP is queued) + timeout specified by the SetCommTimeout() function call. However, since apps can call this function again to change the timeouts, you are right in saying that the queue isn’t necessarily ordered in terms of expiration. I will have to walk the queue if I don’t reorder it. The reason I don’t want to reorder it is because the app code expects that the data for a WriteFile call for com port goes out before a subsequent WriteFile() call for the same com port.

(I assume that if I do a pop and push back on, I can only push back to the tail.)

So, if I instead need to implement a peek function, is it safe to do so as long as I take the lock (the one associated with the lock callback) and release it when I’m done? If I find an IRP that needs to be removed by the queue by my driver because it needs to be completed with an error (due to a timeout: current tick > setcommticktimeout + irp submitted tick count) or without an error (because I can fulfill its request), can I safely do this?

In other words, can I mess around with the cancel safe queue or is the I/O manager only supposed to do that?

thanks very much!

----- Original Message -----
From: Doron Holan
To: Windows System Software Devs Interest List
Sent: Friday, October 28, 2005 4:23 PM
Subject: RE: [ntdev] handling asychronous reads and writes

As for the other questions.

DPCs do not have timers, but timers have DPCs. Look at KeSetTimer(Ex).
There is also a “Timer Objects and DPCs” topic (which is linked off of
the KeInitializeTimerEx topic).

As for iterating over the queue, you can always just pop each request
off the queue, check the time, and if not yet expired, put it back on
the queue. You can also do some optimizations here by sorting the queue
by timeout expiration time. This way you can iterate up to a certain
point in the list w/out needlessly popping off requests which will not
be expired. Also, you can store the current expiration time in your
extension and only return PIRPs which have expired in your
implementation of CsqPeekNextIrp().

d

-----Original Message-----
From: xxxxx@lists.osr.commailto:xxxxx
[mailto:xxxxx@lists.osr.com] On Behalf Of Arlie Davis
Sent: Friday, October 28, 2005 4:08 PM
To: Windows System Software Devs Interest List
Subject: RE: [ntdev] handling asychronous reads and writes

As long as you “own” an IRP, you also “own”
Irp->Tail.Overlay.DriverContext.
This is an array of 4 PVOIDs. You can either store data directly in
this
structure (e.g. cast &Irp->Tail.Overlay.DriverContext[0] to a pointer to
your own structure, as long as the sizeof that structure is less than
sizeof(PVOID[4]), or you can allocate a tracking structure, and store a
pointer to it in DriverContext[0…3]. Your driver ceases to own this
block
when it either completes the IRP (returning it to the issuer) or passes
it
down to another device object.

Be aware that the Cancel-Safe Queue implementation uses DriverContext[3]
for
itself, so you can’t use that field. This constraint is mentioned in
the
docs for IoCsqInitialize.

– arlie

________________________________

From: xxxxx@lists.osr.commailto:xxxxx
[mailto:xxxxx@lists.osr.com] On Behalf Of S. Drasnin
Sent: Friday, October 28, 2005 6:54 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] handling asychronous reads and writes

hi

I have a list of questions below - I hope that somebody with a lot more
driver experience than me can help me out. Any other suggestions would
be
great if you care to offer them.

I am trying to handle asychronous WriteFile() and ReadFile() calls for
my
Virtual Serial over USB driver. It exposes 4 com ports to application,
as
you may remember. The app folks set the timeouts associate the reads
and
writes via a call to SetCommTimeouts().

(1) For the WriteFile() case, the IRPs get put on a cancel safe queue.
However, I need to be able to cancel them if they haven’t been
processed.
So, is there a way for me to store a tick count in with the IRP
somewhere? I
would like to store the tick count of when I put the IRP on a queue. I
could
allocate another stack location and then try to remove it before I
submit
the IRP, but perhaps that is too messy. I could have a separate data
structure to keep track of tick counts for the IRPs on the queue, but
hope I
don’t have to go there.

(2) I was thinking of having a timer go off every 100 ms to check to see
if
I have data available to fulfill the read IRPs (I have a separate
polling
IRP that I keep submitting, that actually asks for data from the device,
independent of any ReadFile() calls). Is this a Timer associated with a
DPC?
Or would I want to use a separate thread or what?

(3) I can maintain a separate queue for every com port. However, it is
easier to keep one queue so that I can serialize USB read/write requests
sent to the USB bus driver, as I am doing now. With one queue, I need to
be
able to do a Peek() into the circular buffer and be able to pull IRPs
out of
there not necessarily from the head of the queue? Is this possible? I
need
to read up on the cancel-safe queues since I see the Peek callback but
it
looks like that is for use by the I/O manager and not my driver. Am I
allowed to peek and pull IRPs off the queue in my driver provided that I
take the lock - or would that screw up the I/O manager? I do not want
to
maintain my own queue because of the warnings about race conditions I’ve
heard about.

Background:
Currently, when an app does a read, the IRP_MJ_READ handler just returns
whatever is in my circular buffer for that particular com port. Since
it’s a
quick operation to do this, I don’t pend the IRP. (But I have to change
this
because I need to support asychronous operations.) Thus, there really
isn’t
IRP_MJ_READs that get submitted down to the usb bus driver due to a
ReadFile(). Because USB requires the host to poll the target for data,
I
have a polling IRP that I submit down the bus driver asking for data - I
take the returned data and stuff it into a circular buffer (one per each
com
port). Then I resubmit the IRP from the completion routine (actually via
a
Work item to get the IRQL level back down to passive).

Thanks in advance.


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256http:

You are currently subscribed to ntdev as: unknown lmsubst tag argument:
‘’
To unsubscribe send a blank email to xxxxx@listsosr.commailto:xxxxx


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256http:

You are currently subscribed to ntdev as: xxxxx@microsoft.commailto:xxxxx
To unsubscribe send a blank email to xxxxx@listsosr.commailto:xxxxx


Questions? First check the Kernel Driver FAQ at http://www.osronline.com/article.cfm?id=256http:

You are currently subscribed to ntdev as: unknown lmsubst tag argument: ‘’
To unsubscribe send a blank email to xxxxx@listsosr.commailto:xxxxx


Questions? First check the Kernel Driver FAQ at http://www.osronline.com/article.cfm?id=256http:

You are currently subscribed to ntdev as: unknown lmsubst tag argument: ‘’
To unsubscribe send a blank email to xxxxx@lists.osr.commailto:xxxxx


Questions? First check the Kernel Driver FAQ at http://www.osronline.com/article.cfm?id=256http:

You are currently subscribed to ntdev as: unknown lmsubst tag argument: ‘’
To unsubscribe send a blank email to xxxxx@lists.osr.commailto:xxxxx</mailto:xxxxx></http:></mailto:xxxxx></http:></mailto:xxxxx></http:></mailto:xxxxx></mailto:xxxxx></http:></mailto:xxxxx></http:></mailto:xxxxx></mailto:xxxxx></mailto:xxxxx></mailto:xxxxx></mailto:xxxxx>

Passing the retrieval criteria in the context is a fine idea.

d


From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of S. Drasnin
Sent: Sunday, October 30, 2005 6:43 PM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] handling asychronous reads and writes

Thanks for the info - and especially for the gotcha about the lock…
?
So, the problem I’m trying to solve isn’t that unique. There must be other drivers doing this. What approach do people normally take? I could see that they roll their own queues rather than using the using the cancel safe queue.
?
For now, I’m going to explore Scott’s idea of using?a peek context that passes in a criteria for matching (I.e. the number of bytes, the expiration tick value from the SetCommTimeout() call from the application layer…) that is used to determine what IRP (if any) to return.
?
thanks
?
----- Original Message -----
From: Doron Holan
To: Windows System Software Devs Interest List
Sent: Sunday, October 30, 2005 3:29 PM
Subject: RE: [ntdev] handling asychronous reads and writes

The CSQ is your object, not the I/O manager’s.? You control insertion and removal into the IOCSQ.? The only direct access the io manager has to the CSQ is via the irp’s cancel routine.? You can easily acquire the queue lock and walk the list of requests directly.? Removal of a request from the queue is another question while you are holding the queue lock b/c the CSQ removal API is not callable while the lock is held.

d


From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of S. Drasnin
Sent: Friday, October 28, 2005 4:51 PM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] handling asychronous reads and writes

hi

Thanks Doron and Arlie for the quick/helpful replies back.

The timeout value will be: (time IRP is queued) + timeout specified by the SetCommTimeout() function call. However, since apps can call this function again to change the timeouts, you are right in saying that the queue isn’t necessarily ordered in terms of expiration. I will have to walk the queue if I don’t reorder it. The reason I don’t want to reorder it is because the app code expects that the data for a WriteFile call for com port goes out before a subsequent WriteFile() call for the same com port.

(I assume that if I do a pop and push back on, I can only push back to the tail.)

So, if I instead need to implement a peek function, is it safe to do so as long as I take the lock (the one associated with the lock callback) and release it when I’m done? If I find an IRP that needs to be removed by the queue by my driver because it needs to be completed with an error (due to a timeout: current tick > setcommticktimeout + irp submitted tick count) or without an error (because I can fulfill its request), can I safely do this?

In other words, can I mess around with the cancel safe queue or is the I/O manager only supposed to do that?

thanks very much!

----- Original Message -----
From: Doron Holan
To: Windows System Software Devs Interest List
Sent: Friday, October 28, 2005 4:23 PM
Subject: RE: [ntdev] handling asychronous reads and writes

As for the other questions.

DPCs do not have timers, but timers have DPCs. Look at KeSetTimer(Ex).
There is also a “Timer Objects and DPCs” topic (which is linked off of
the KeInitializeTimerEx topic).

As for iterating over the queue, you can always just pop each request
off the queue, check the time, and if not yet expired, put it back on
the queue. You can also do some optimizations here by sorting the queue
by timeout expiration time. This way you can iterate up to a certain
point in the list w/out needlessly popping off requests which will not
be expired. Also, you can store the current expiration time in your
extension and only return PIRPs which have expired in your
implementation of CsqPeekNextIrp().

d

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Arlie Davis
Sent: Friday, October 28, 2005 4:08 PM
To: Windows System Software Devs Interest List
Subject: RE: [ntdev] handling asychronous reads and writes

As long as you “own” an IRP, you also “own”
Irp->Tail.Overlay.DriverContext.
This is an array of 4 PVOIDs. You can either store data directly in
this
structure (e.g. cast &Irp->Tail.Overlay.DriverContext[0] to a pointer to
your own structure, as long as the sizeof that structure is less than
sizeof(PVOID[4]), or you can allocate a tracking structure, and store a
pointer to it in DriverContext[0…3]. Your driver ceases to own this
block
when it either completes the IRP (returning it to the issuer) or passes
it
down to another device object.

Be aware that the Cancel-Safe Queue implementation uses DriverContext[3]
for
itself, so you can’t use that field. This constraint is mentioned in
the
docs for IoCsqInitialize.

– arlie


From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of S. Drasnin
Sent: Friday, October 28, 2005 6:54 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] handling asychronous reads and writes

hi

I have a list of questions below - I hope that somebody with a lot more
driver experience than me can help me out. Any other suggestions would
be
great if you care to offer them.

I am trying to handle asychronous WriteFile() and ReadFile() calls for
my
Virtual Serial over USB driver. It exposes 4 com ports to application,
as
you may remember. The app folks set the timeouts associate the reads
and
writes via a call to SetCommTimeouts().

(1) For the WriteFile() case, the IRPs get put on a cancel safe queue.
However, I need to be able to cancel them if they haven’t been
processed.
So, is there a way for me to store a tick count in with the IRP
somewhere? I
would like to store the tick count of when I put the IRP on a queue. I
could
allocate another stack location and then try to remove it before I
submit
the IRP, but perhaps that is too messy. I could have a separate data
structure to keep track of tick counts for the IRPs on the queue, but
hope I
don’t have to go there.

(2) I was thinking of having a timer go off every 100 ms to check to see
if
I have data available to fulfill the read IRPs (I have a separate
polling
IRP that I keep submitting, that actually asks for data from the device,
independent of any ReadFile() calls). Is this a Timer associated with a
DPC?
Or would I want to use a separate thread or what?

(3) I can maintain a separate queue for every com port. However, it is
easier to keep one queue so that I can serialize USB read/write requests
sent to the USB bus driver, as I am doing now. With one queue, I need to
be
able to do a Peek() into the circular buffer and be able to pull IRPs
out of
there not necessarily from the head of the queue? Is this possible? I
need
to read up on the cancel-safe queues since I see the Peek callback but
it
looks like that is for use by the I/O manager and not my driver. Am I
allowed to peek and pull IRPs off the queue in my driver provided that I
take the lock - or would that screw up the I/O manager? I do not want
to
maintain my own queue because of the warnings about race conditions I’ve
heard about.

Background:
Currently, when an app does a read, the IRP_MJ_READ handler just returns
whatever is in my circular buffer for that particular com port. Since
it’s a
quick operation to do this, I don’t pend the IRP. (But I have to change
this
because I need to support asychronous operations.) Thus, there really
isn’t
IRP_MJ_READs that get submitted down to the usb bus driver due to a
ReadFile(). Because USB requires the host to poll the target for data,
I
have a polling IRP that I submit down the bus driver asking for data - I
take the returned data and stuff it into a circular buffer (one per each
com
port). Then I resubmit the IRP from the completion routine (actually via
a
Work item to get the IRQL level back down to passive).

Thanks in advance.


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

You are currently subscribed to ntdev as: unknown lmsubst tag argument:
‘’
To unsubscribe send a blank email to xxxxx@listsosr.com


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

You are currently subscribed to ntdev as: xxxxx@microsoft.com
To unsubscribe send a blank email to xxxxx@listsosr.com


Questions? First check the Kernel Driver FAQ at http://www.osronline.com/article.cfm?id=256

You are currently subscribed to ntdev as: unknown lmsubst tag argument: ‘’
To unsubscribe send a blank email to xxxxx@listsosr.com


Questions? First check the Kernel Driver FAQ at http://www.osronline.com/article.cfm?id=256

You are currently subscribed to ntdev as: unknown lmsubst tag argument: ‘’
To unsubscribe send a blank email to xxxxx@listsosr.com


Questions? First check the Kernel Driver FAQ at http://www.osronline.com/article.cfm?id=256

You are currently subscribed to ntdev as: unknown lmsubst tag argument: ‘’
To unsubscribe send a blank email to xxxxx@listsosr.com


Questions? First check the Kernel Driver FAQ at http://www.osronline.com/article.cfm?id=256

You are currently subscribed to ntdev as: unknown lmsubst tag argument: ‘’
To unsubscribe send a blank email to xxxxx@lists.osr.com