Hi Oliver, I decided to see how other drivers deal with this usb_unlink_urb
issue.  The first thing I looked was devio.c.  And guess what, it looks like
it assumes that the completion handler has completed by the time
usb_unlink_urb finishes:

static void destroy_async (struct dev_state *ps, struct list_head *list)
{
        struct async *as;
        unsigned long flags;

        spin_lock_irqsave(&ps->lock, flags);
        while (!list_empty(list)) {
                as = list_entry(list->next, struct async, asynclist);
                list_del_init(&as->asynclist);
                spin_unlock_irqrestore(&ps->lock, flags);
                /* usb_unlink_urb calls the completion handler with status == -ENOENT 
*/
                usb_unlink_urb(as->urb);
                spin_lock_irqsave(&ps->lock, flags);
        }
        spin_unlock_irqrestore(&ps->lock, flags);
        while ((as = async_getcompleted(ps)))   <=== assumes completion handler 
finished before this call
                free_async(as);

Hmm, I wonder what the chances are that the next driver I look at
suffers from the same kind of problem.

All the best,

Duncan.


On Friday 10 January 2003 14:55, Oliver Neukum wrote:
> Am Freitag, 10. Januar 2003 13:21 schrieb Duncan Sands:
> > > I am afraid I do not agree. Your reasoning is correct only on UP.
> > > If the code in question runs on another CPU, you are in trouble.
> >
> > It all depends on the semantics of usb_unlink_urb.  Consider the
> > patch below.  Is this any better?  Maybe not: if usb_unlink_urb
> > returns before the completion handler (running on another CPU)
> > reaches the tasklet_schedule statement, then what is to stop
> > the tasklet being scheduled by the completion handler after the
> > tasklet_kill?  Nothing.  So it all depends on whether or
> > not usb_unlink_urb guarantees that the completion handler has
> > finished running before it (usb_unlink_urb) returns.
>
>       if (urb->status != -EINPROGRESS) {
>               retval = -EBUSY;
>               goto done;
>       }
> from hcd.c
>
> So, usb_unlink_urb() will explicitely return if the completion handler
> is running. To be safe you need something like:
>
> (in disconnect() )
> spin_lock_irq(...);
> descriptor->disconnected = 1;
> tasklet_kill(...);
> spin_unlock_irq(...);
>
> (in the completion handler)
> spin_lock(...);
> if (!descriptor->disconnected)
>       tasklet_schedule(...);
> spin_unlock(...);
>
>       HTH
>               Oliver


-------------------------------------------------------
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