On Wed, 29 Jan 2003, David Brownell wrote:

> > I don't think I understand your objection.  Are you saying that if a
> > driver calls usb_unlink_urb() while the urb's completion handler is
> > running, then back when the handler was originally called the value of
> > urb->status wasn't -ECONNRESET or -ENOENT? 
> 
> When a task (or even IRQ handler) on one CPU tries to unlink, the request
> may be in MANY stages of completing on another CPU.  That shouldn't matter
> at all to whatever is unlinking ... in your patch, it _did_ matter.

Hmm...  I'm beginning to suspect that you misread my patch (or possibly
that I miswrote it).  Yes, an urb can be in any of several different
stages of completing.  For the sake of argument, let's define some of
these stages:

        0: Starts when the hardware finishes its USB transaction and 
           signals an interrupt.

        1: Starts when the interrupt handler changes urb->status from 
           -EINPROGRESS to something else.

        2: Starts when usb_hcd_giveback_urb() calls the completion handler 
           (or in my patch, locks urb->handler_lock).

After the handler returns (or urb->handler_lock is released), the 
completion process is over and the urb is idle, assuming it wasn't 
resubmitted.

As far as I'm concerned (i.e., looking at things strictly from the 
software point of view), during stage 0 the urb is essentially still 
active; the completion process has not yet begun.  Agreed, an unlink call 
down to the low-level driver at this time might produce an error code, but 
that call would still have to be made.  My patch handles this correctly;
in fact, the existing code is unchanged.

Stage 1.  I discuss this below.

Stage 2.  The problems of handling this correctly are so messy, especially
when you consider the possibility that the completion handler might have
resubmitted the urb, that I basically punted.  The patch makes
hcd_unlink_urb() spin until stage 2 is over, thus essentially pretending
that the unlink call didn't arrive during stage 2 after all.  Since the
handler must be running on a different cpu, there's no way the caller can
tell exactly what the relative order of the two events (call to unlink vs.
handler returning) actually was, without using some very dubious
synchronization mechanism.  Is this what you object to?

> > That's clearly unavoidable and
> > hardly a violation of the API spec; after all, the instance of the urb for
> > which the handler is running _wasn't_ cancelled (at least, not by this
> > call to usb_unlink_urb()).
> 
> But you're returning a success code, reporting that it was. 

No, I'm not.  Or at least, I don't intend to.

We're talking about unlinking during stage 1 here.  The code sees that 
urb->status != -EINPROGRESS, so it returns -EBUSY to its caller 
(indicating that the urb was already in the process of finishing up) -- 
that's not a success code -- and it leaves urb->status alone (since the 
urb didn't finish as a result of the call to usb_unlink_urb()).

> Ignoring
> the issue of whether the unlink request is synchronous, discarding the
> current -EBUSY return code means that drivers written to block until
> they get an -ECONNRESET or -ENOENT completion would never wake up.

That's why I think you are misreading the patch.  It doesn't discard the 
current -EBUSY return code.

> > Maybe it doesn't really need solving.  But as things stand, the API spec 
> > probably could use some revision.  It says:
> > 
> >  * When the URB_ASYNC_UNLINK transfer flag for the URB is clear, this
> >  * request is synchronous.  Success is indicated by returning zero,
> >  * at which time the urb will have been unlinked,
> >  * and the completion function will see status -ENOENT.
> > 
> > I note that this makes no guarantees about when the completion function 
> > will run with respect to the return from usb_unlink_urb(); it only says 
> > that the status will be -ENOENT and that the urb will have been unlinked.
> 
> Maybe it should have said completion function "will have seen", but
> I don't naturally gravitate to the future perfect tense!  :)
> 
> But you seemed to be concerned about when the completion function
> finishes, while all that does is talk about when it starts.

It doesn't even do that.  It says nothing about when the completion
function will run or will return; it only says that the function will see
status -ENOENT.  Yes, I am concerned about when the completion function
finishes, since that's what matters to a driver.  If we can't guarantee
that the completion function will have finished when a synchronous unlink
returns (with a success code), then there's no reason for a driver _ever_
to use a synchronous unlink.

> With
> HCDs using the "hcd.c" code we know that answer.  I'd not object
> to requiring all HCDs to do that, since I'm not involved with any
> of the ones that would need to change.

I'm not familiar with that part of the core.  Can you tell me what other
ones would need to change, and where the appropriate source files are?

Alan Stern



-------------------------------------------------------
This SF.NET email is sponsored by:
SourceForge Enterprise Edition + IBM + LinuxWorld = Something 2 See!
http://www.vasoftware.com
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to