Oliver Neukum wrote:
Am Montag, 13. Januar 2003 00:03 schrieb David Brownell:

Let me explain.
The first problem we avoid is with unloading. We want to be sure that
the completion handler is not running after return from usb_unlink_urb().
If we wish to make the guarantee, usb_unlink_urb() must not simply
fail if the completion handler is running. A synchronous unlink must wait.
That is, you want to solve the general "callback into module
being unloaded" problem.

Shouldn't the module unload logic be handling this already, by
forcing every CPU to have scheduled a new task before letting
unloads complete?  That is, by calling synchronize_kernel().


The second problem we fix is with resubmission from the completion
handler. If we have a state for unlinked during completion, we can fail
resubmission. Thus we kill races with disconnect in rx paths.
As Alan pointed out, the resubmit logic needs to be informed that
resubmission is no longer desired ... just like a timer resubmit.

So this issue is already in the hands of that device driver.  It's
easy enough to solve (flag tested under spinlock in completion),
and already a requirement for drivers ... so the usb core/hcd logic
doesn't need to add overhead for that reason.


Likewise, "hcd.c" certainly guarantees that for _successful synchronous_
unlinks, the completion handler returned.  Any non-"hcd" drivers need
to provide that guarantee some other way.

Correct. But we want it always.
You're being unreasonable.

 - It clearly mustn't be a guarantee for asynchronous unlinks.

 - Just as clearly, there are fault cases where unlinks can't
   possibly succeed (urb isn't linked, etc).

Or you're still not explaining key parts of what you're saying.


	Unless a less trivial urb
state machine is used, like:

	IDLE -> INITTED -> SUBMITTED -> COMPLETING -> DONE

so that unlinking either accelerates transition to DONE
or (new feature as-yet-undiscussed here) prevents going to
SUBMITTED in the first place.  That feature would suffice
to let urbs be used for some basic task synchronization;
right now they can't, additional data structures are needed.

Interesting. How would that be used?
Defining a new synchronous call, something like

  int usb_perform_urb (struct urb *urb, long timeout);

One task puts the urb into INITTED stage and then
exposes it (locked write to a pointer?) to other tasks
at some point before it calls usb_perform_urb().

Then any other thread can safely usb_unlink_urb() to
prevent the usb-related activity of the first urb,
without one of the start-to-unlink races you noticed
the other day .. since it'd work even in the case that
the urb hadn't yet been submitted.  (Scheduling delays,
passing urbs around like futures, whatever.)

The current usb_{bulk,control}_msg() calls could just
call that, replacing a lot of crufty logic ... and so
could usb-storage, replacing its private variants of
the usb_*_msg() calls.

And any driver that wanted to use synchronous models
could safely use usb_perform_urb(), knowing their
disconnect() calls would usb_unlink_urb() directly.


How's the transition from IDLE to INITTED done?
usb_init_*_urb() would do it, and there'd be a
new call drivers would use to transition DONE or
COMPLETING into INITTED, before resubmit.


Why is DONE different from IDLE?
It's partially initted; DONE-->INITTED doesn't
need things like spinlock re-init.


How is resubmission in completion handled?
Mark the urb as really INITTED first.

- Dave








-------------------------------------------------------
This SF.NET email is sponsored by: Take your first step towards giving your online business a competitive advantage. Test-drive a Thawte SSL certificate - our easy online guide will show you how. Click here to get started: http://ads.sourceforge.net/cgi-bin/redirect.pl?thaw0027en
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to