On Wed, 15 Jan 2003, David Brownell wrote:

> Alan Stern wrote:
> 
> > This is where my lack of knowledge of the details underlying the usb core
> > shows through.  Okay, looking at hcd.c I see where urb_unlink() is called
> > and how it releases the bandwidth.  I'm surprised; is it really supposed
> > to work this way?
> 
> At this point, only "uhci-hcd" relies on that and I have a note somewhere
> that it doesn't actually reserve such bandwidth correctly.  The basic
> problem is that the model of those bandwidth reservation calls is wrong.
> 
> (Especially so for ISO ... consider that two queued ISO requests will
> get accounted as twice the bandwidth of one, rather than just one
> being used serially...)

Okay, let's forget about bandwidth reservation for the time being.

> As for the other posts on this thread, I hope to have time to read
> them later.  Adding more spinlocks is (more often than not) a Bad Thing,
> deadlock-prone.  It's not clear to me why urb->lock wouldn't suffice,
> and there's some other wierdness being proposed.

I agree that using a spinlock to solve our problem is an unorthodox
approach.  We are taking care to avoid deadlocks -- not much of a problem
here because the new spinlock is only used in two places in the code.  
urb->lock doesn't solve the problem at hand, because it is required to be
unlocked while the completion handler runs (so that the handler can
resubmit its urb) -- but that is precisely the time period that we need
our lock to be held.

On the face of it, since what we are trying to do is block a thread of
execution until some subroutine finishes, a wait queue would appear to be
the tool of choice.  Unfortunately, it won't work here.  First think of
where the wait queue header would have to be stored: a synchronous call to
usb_unlink_urb() needs to get on the queue, even if the completion handler
has already started to run.  Hence the only place to store the queue
header is in the urb itself.  (An alternative location would be on the
stack of giveback_urb, but that's not possible once the handler has
started.)

Now consider the problem of an urb that is always resubmitted by its
completion handler.  When the time comes to unload the driver, the driver
will make a synchronous call to usb_unlink_urb().  Suppose that call
happens just after the handler resubmitted the urb and before the handler
has returned.  The unlink routine will put itself on the urb's wait queue,
and hence will be awakened as soon as the resubmitting handler returns,
_not_ after the handler for the resubmitted urb has run.  I can't see any
reasonable way to get around this using wait queues.

But a spinlock solves the problem just fine.  If usb_unlink_urb() is
called for an urb that has not yet completed, then it chains itself into
the completion routine and waits as usual.  If it is called for a
completed urb, it changes the internal_state so that resubmission will
fail, and spins on the handler_lock -- which is released immediately after
the completion handler returns.

I think this is a rather simple solution to a complex problem, and while
slightly unorthodox it does not seem at all wierd (IMHO).  In fact, it
solves a problem that, as far as I know, is completely unsolved in the
Linux kernel at large -- namely, how can you tell when an interrupt
routine, bottom-half handler, or kernel thread has exited?  The routine
can signal a struct completion or a struct semaphore to inform you it is
about to exit, but for all you know it could then have been preempted
before executing the Return instruction and hence still be alive.  You
can't allow your module to be unloaded until after that Return, but
there's no way in general to know that it has occurred.  Practically all
existing drivers just rely on the fact that this kind of preemption is
very rare and does not last long -- less time, at any rate, than unloading
a module requires.

The only sure-fire way to know is to have the callback routine's caller
inform you, and that's what synchronous usb_unlink_urb() does.

Alan Stern



-------------------------------------------------------
This SF.NET email is sponsored by: Thawte.com
Understand how to protect your customers personal information by implementing
SSL on your Apache Web Server. Click here to get our FREE Thawte Apache 
Guide: http://ads.sourceforge.net/cgi-bin/redirect.pl?thaw0029en
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to