On Sat, Aug 21, 2010 at 08:25:23AM +0000, Jacob Meuser wrote:
> +volatile int usb_run_tasks;
> +volatile int discover_pending = 0;

Do these really need to be volatile?

+/* called by usbd_finish when lasst usb is detached */

s/lasst/last/

+void
+usb_end_tasks(void)
+{
+       usb_run_tasks = 0;
+}

I think we need a wakeup(&usb_run_tasks) after the assignment.

> -     s = splusb();
> -     for (;;) {
> -             task = TAILQ_FIRST(&usb_all_tasks);
> -             if (task == NULL) {
> -                     tsleep(&usb_all_tasks, PWAIT, "usbtsk", 0);
> -                     task = TAILQ_FIRST(&usb_all_tasks);
> +     while (usb_run_tasks) {
> +             s = splusb();
> +             while (usb_run_tasks &&
> +                 (!TAILQ_EMPTY(&usb_hub_tasks) ||
> +                 !TAILQ_EMPTY(&usb_device_tasks))) {
> +
> +                     task = TAILQ_FIRST(&usb_hub_tasks);
> +                     while (task != NULL && usb_run_tasks) {
> +                             TAILQ_REMOVE(&usb_hub_tasks, task, next);
> +                             task->onqueue = 0;
> +                             splx(s);
> +                             task->fun(task->arg);
> +                             s = splusb();
> +                             task = TAILQ_FIRST(&usb_hub_tasks);
> +                     }
> +
> +                     task = TAILQ_FIRST(&usb_device_tasks);
> +                     while (task != NULL && usb_run_tasks) {
> +                             TAILQ_REMOVE(&usb_device_tasks, task, next);
> +                             task->onqueue = 0;
> +                             splx(s);
> +                             task->fun(task->arg);
> +                             s = splusb();
> +                             if (!TAILQ_EMPTY(&usb_hub_tasks))
> +                                     break;
> +                             task = TAILQ_FIRST(&usb_device_tasks);
> +                     }
>               }
> -             DPRINTFN(2,("usb_task_thread: woke up task=%p\n", task));
> -             if (task != NULL) {
> -                     TAILQ_REMOVE(&usb_all_tasks, task, next);
> -                     task->onqueue = 0;
> -                     splx(s);
> -                     task->fun(task->arg);
> -                     s = splusb();
> +             splx(s);
> +
> +             if (usb_run_tasks) {
> +                     /* XXX Is not timing out too optimistic? */
> +                     tsleep(&usb_run_tasks, PWAIT, "usbtsk", 0);
> +                     DPRINTFN(2,("%s: woke up\n", __func__));
>               }
>       }

If a bunch of device tasks get enqueued and then while we're running
them, a discover task gets enqueued, the device tasks will finish
running before we run the discover task.

How about writing the task thread loop like this:

        s = splusb();
        for (usb_run_tasks) {
                if ((task = TAILQ_FIRST(&usb_hub_tasks)) != NULL)
                        TAILQ_REMOVE(&usb_hub_tasks, task, next);
                else if ((task = TAILQ_FIRST(&usb_device_tasks)) != NULL)
                        TAILQ_REMOVE(&usb_device_tasks, task, next);
                else {
                        tsleep(&usb_run_tasks, PWAIT, "usbtsk", 0);
                        continue;
                }

                task->onqueue = 0;
                splx(s);
                task->fun(task->arg);
                s = splusb();
        }
        splx(s);

Also, is there a chance that there are tasks still enqueued when
usb_end_tasks() is called?  Do they need any cleanup?

Reply via email to