From bd7db3a7ec4c1d4dee0aa7ef53c547cb353ad2ee Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Mon, 21 Apr 2008 15:23:22 +0000 Subject: [PATCH] Add an interlock for certain usb task operations. --- sys/bus/usb/usb.c | 67 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 16 deletions(-) diff --git a/sys/bus/usb/usb.c b/sys/bus/usb/usb.c index b7517ccc67..fbdc8fd875 100644 --- a/sys/bus/usb/usb.c +++ b/sys/bus/usb/usb.c @@ -1,7 +1,7 @@ /* * $NetBSD: usb.c,v 1.68 2002/02/20 20:30:12 christos Exp $ * $FreeBSD: src/sys/dev/usb/usb.c,v 1.106 2005/03/27 15:31:23 iedowse Exp $ - * $DragonFly: src/sys/bus/usb/usb.c,v 1.39 2007/07/03 19:28:16 hasso Exp $ + * $DragonFly: src/sys/bus/usb/usb.c,v 1.40 2008/04/21 15:23:22 dillon Exp $ */ /* Also already merged from NetBSD: @@ -368,15 +368,21 @@ usb_add_task(usbd_device_handle dev, struct usb_task *task, int queue) crit_enter(); + /* + * Wait if task is currently executing + */ + while (task->queue == -2) + tsleep(task, 0, "usbwttsk", hz); + taskq = &usb_taskq[queue]; if (task->queue == -1) { DPRINTFN(2,("usb_add_task: task=%p\n", task)); TAILQ_INSERT_TAIL(&taskq->tasks, task, next); task->queue = queue; + wakeup(&taskq->tasks); } else { DPRINTFN(3,("usb_add_task: task=%p on q\n", task)); } - wakeup(&taskq->tasks); crit_exit(); } @@ -389,18 +395,27 @@ usb_do_task(usbd_device_handle dev, struct usb_task *task, int queue, crit_enter(); + /* + * Wait if task is currently executing + */ + while (task->queue == -2) + tsleep(task, 0, "usbwttsk", hz); + taskq = &usb_taskq[queue]; if (task->queue == -1) { DPRINTFN(2,("usb_add_task: task=%p\n", task)); TAILQ_INSERT_TAIL(&taskq->tasks, task, next); task->queue = queue; + wakeup(&taskq->tasks); } else { DPRINTFN(3,("usb_add_task: task=%p on q\n", task)); } - wakeup(&taskq->tasks); - /* Wait until task is finished */ - tsleep((&taskq->tasks + 1), 0, "usbdotsk", time_out); + /* + * Wait until task is completely finished + */ + while (task->queue != -1) + tsleep(task, 0, "usbwttsk", hz); crit_exit(); } @@ -409,6 +424,16 @@ void usb_rem_task(usbd_device_handle dev, struct usb_task *task) { crit_enter(); + + /* + * Wait if task is currently executing, we can't remove it now! + */ + while (task->queue == -2) + tsleep(task, 0, "usbwttsk", hz); + + /* + * Remove the task if it has not started executing yet. + */ if (task->queue != -1) { TAILQ_REMOVE(&usb_taskq[task->queue].tasks, task, next); task->queue = -1; @@ -475,20 +500,30 @@ usb_task_thread(void *arg) DPRINTF(("usb_task_thread: start taskq %s\n", taskq->name)); while (usb_ndevs > 0) { - task = TAILQ_FIRST(&taskq->tasks); - if (task == NULL) { + /* + * Wait for work + */ + if ((task = TAILQ_FIRST(&taskq->tasks)) == NULL) { tsleep(&taskq->tasks, 0, "usbtsk", 0); - task = TAILQ_FIRST(&taskq->tasks); + continue; } + + /* + * De-queue, mark as currently executing and run the + * function. + */ DPRINTFN(2,("usb_task_thread: woke up task=%p\n", task)); - if (task != NULL) { - TAILQ_REMOVE(&taskq->tasks, task, next); - task->queue = -1; - crit_exit(); - task->fun(task->arg); - crit_enter(); - wakeup((&taskq->tasks + 1)); - } + TAILQ_REMOVE(&taskq->tasks, task, next); + task->queue = -2; + crit_exit(); + task->fun(task->arg); + + /* + * Mark as complete and wakeup anyone waiting. + */ + crit_enter(); + task->queue = -1; + wakeup(task); } crit_exit(); -- 2.41.0