From owner-freebsd-usb@FreeBSD.ORG Fri Nov 5 18:29:32 2010 Return-Path: Delivered-To: freebsd-usb@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id C2C5B106566C; Fri, 5 Nov 2010 18:29:32 +0000 (UTC) (envelope-from hselasky@c2i.net) Received: from swip.net (mailfe07.swip.net [212.247.154.193]) by mx1.freebsd.org (Postfix) with ESMTP id D42F58FC1A; Fri, 5 Nov 2010 18:29:31 +0000 (UTC) X-Cloudmark-Score: 0.000000 [] X-Cloudmark-Analysis: v=1.1 cv=sEolSJAlcSxSMaOm1MQ0bvrIu+BNAN+OqG2UAUgC4Ok= c=1 sm=1 a=FberXtVRn-wA:10 a=CL8lFSKtTFcA:10 a=i9M/sDlu2rpZ9XS819oYzg==:17 a=Cw8rU7oRz3VboNDMIlAA:9 a=MUlSQjhuJp0JbwSJUxwIolEPeYMA:4 a=wPNLvfGTeEIA:10 a=FcgzJa1LcXe6IDLysl4A:9 a=XnCYU3IuQVv1LWxiYhsA:7 a=klG2om15o0QNuV1ZETSHBZYqC58A:4 a=i9M/sDlu2rpZ9XS819oYzg==:117 Received: from [188.126.198.129] (account mc467741@c2i.net HELO laptop002.hselasky.homeunix.org) by mailfe07.swip.net (CommuniGate Pro SMTP 5.2.19) with ESMTPA id 45156194; Fri, 05 Nov 2010 19:29:30 +0100 From: Hans Petter Selasky To: freebsd-current@freebsd.org Date: Fri, 5 Nov 2010 19:30:38 +0100 User-Agent: KMail/1.13.5 (FreeBSD/8.1-STABLE; KDE/4.4.5; amd64; ; ) References: <201011012054.59551.hselasky@c2i.net> <201011051836.39697.hselasky@c2i.net> In-Reply-To: <201011051836.39697.hselasky@c2i.net> X-Face: +~\`s("[*|O,="7?X@L.elg*F"OA\I/3%^p8g?ab%RN'(; _IjlA: hGE..Ew, XAQ*o#\/M~SC=S1-f9{EzRfT'|Hhll5Q]ha5Bt-s|oTlKMusi:1e[wJl}kd}GR Z0adGx-x_0zGbZj'e(Y[(UNle~)8CQWXW@:DX+9)_YlB[tIccCPN$7/L' MIME-Version: 1.0 Content-Type: Multipart/Mixed; boundary="Boundary-00=_O1E1M5DxgzaX2zh" Message-Id: <201011051930.38530.hselasky@c2i.net> Cc: Weongyo Jeong , Matthew Fleming , freebsd-usb@freebsd.org, freebsd-arch@freebsd.org Subject: Re: [RFC] Outline of USB process integration in the kernel taskqueue system X-BeenThere: freebsd-usb@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: FreeBSD support for USB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 05 Nov 2010 18:29:32 -0000 --Boundary-00=_O1E1M5DxgzaX2zh Content-Type: Text/Plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Hi, In the patch attached to this e-mail I included Matthew Fleming's patch aswell. 1) I renamed taskqueue_cancel() into taskqueue_stop(), hence that resembles the words of the callout and USB API's terminology for doing the same. 2) I turns out I need to have code in subr_taskqueue.c to be able to make the operations atomic. 3) I did not update the manpage in this patch. Will do that before a commit. 4) My patch implements separate state keeping in "struct task_pair", which avoids having to change any KPI's for now, like suggested by John Baldwin I think. 5) In my implementation I hard-coded the priority argument to zero, so that enqueuing is fast. Comments are welcome! --HPS --Boundary-00=_O1E1M5DxgzaX2zh Content-Type: text/x-patch; charset="iso-8859-1"; name="0001-Implement-taskqueue_pair.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="0001-Implement-taskqueue_pair.patch" === kern/subr_taskqueue.c ================================================================== --- kern/subr_taskqueue.c (revision 214796) +++ kern/subr_taskqueue.c (local) @@ -275,6 +275,25 @@ return (0); } +int +taskqueue_stop(struct taskqueue *queue, struct task *task) +{ + int retval = 0; + + TQ_LOCK(queue); + + if (task->ta_pending != 0) { + STAILQ_REMOVE(&queue->tq_queue, task, task, ta_link); + task->ta_pending = 0; + } + if (task_is_running(queue, task)) + retval = EBUSY; + + TQ_UNLOCK(queue); + + return (retval); +} + void taskqueue_drain(struct taskqueue *queue, struct task *task) { @@ -288,6 +307,113 @@ TQ_UNLOCK(queue); } + +int +taskqueue_pair_enqueue(struct taskqueue *queue, struct task_pair *tp) +{ + struct task *task; + int retval; + int j; + + TQ_LOCK(queue); + + j = 0; + if (tp->tp_task[0].ta_pending > 0) + j |= 1; + if (tp->tp_task[1].ta_pending > 0) + j |= 2; + + if (j == 0) { + /* No entries are queued. Just pick a last task. */ + tp->tp_last = 0; + /* Re-queue the last queued task. */ + task = &tp->tp_task[0]; + } else if (j == 1) { + /* There is only one task pending and the other becomes last. */ + tp->tp_last = 1; + /* Re-queue the last queued task. */ + task = &tp->tp_task[1]; + } else if (j == 2) { + /* There is only one task pending and the other becomes last. */ + tp->tp_last = 0; + /* Re-queue the last queued task. */ + task = &tp->tp_task[0]; + } else { + /* Re-queue the last queued task. */ + task = &tp->tp_task[tp->tp_last]; + STAILQ_REMOVE(&queue->tq_queue, task, task, ta_link); + } + + STAILQ_INSERT_TAIL(&queue->tq_queue, task, ta_link); + + retval = tp->tp_last + 1; + /* store the actual order in the pending count */ + task->ta_pending = retval; + + if ((queue->tq_flags & TQ_FLAGS_BLOCKED) == 0) + queue->tq_enqueue(queue->tq_context); + else + queue->tq_flags |= TQ_FLAGS_PENDING; + + TQ_UNLOCK(queue); + + return (retval); +} + +int +taskqueue_pair_stop(struct taskqueue *queue, struct task_pair *tp) +{ + struct task *task; + int retval = 0; + + TQ_LOCK(queue); + + task = &tp->tp_task[0]; + if (task->ta_pending != 0) { + STAILQ_REMOVE(&queue->tq_queue, task, task, ta_link); + task->ta_pending = 0; + } + if (task_is_running(queue, task)) + retval = EBUSY; + + task = &tp->tp_task[1]; + if (task->ta_pending != 0) { + STAILQ_REMOVE(&queue->tq_queue, task, task, ta_link); + task->ta_pending = 0; + } + if (task_is_running(queue, task)) + retval = EBUSY; + + TQ_UNLOCK(queue); + + return (retval); +} + +void +taskqueue_pair_drain(struct taskqueue *queue, struct task_pair *tp) +{ + struct task *task; + + if (!queue->tq_spin) + WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, __func__); + + TQ_LOCK(queue); +top: + task = &tp->tp_task[0]; + if (task->ta_pending != 0 || task_is_running(queue, task)) { + TQ_SLEEP(queue, task, &queue->tq_mutex, PWAIT, "-", 0); + goto top; + } + + task = &tp->tp_task[1]; + if (task->ta_pending != 0 || task_is_running(queue, task)) { + TQ_SLEEP(queue, task, &queue->tq_mutex, PWAIT, "-", 0); + goto top; + } + + TQ_UNLOCK(queue); +} + static void taskqueue_swi_enqueue(void *context) { === sys/_task.h ================================================================== --- sys/_task.h (revision 214796) +++ sys/_task.h (local) @@ -51,4 +51,9 @@ void *ta_context; /* (c) argument for handler */ }; +struct task_pair { + struct task tp_task[2]; + int tp_last; /* (q) index of last queued task */ +}; + #endif /* !_SYS__TASK_H_ */ === sys/taskqueue.h ================================================================== --- sys/taskqueue.h (revision 214796) +++ sys/taskqueue.h (local) @@ -53,7 +53,11 @@ void *context); int taskqueue_start_threads(struct taskqueue **tqp, int count, int pri, const char *name, ...) __printflike(4, 5); +int taskqueue_pair_enqueue(struct taskqueue *queue, struct task_pair *tp); +int taskqueue_pair_stop(struct taskqueue *queue, struct task_pair *tp); +void taskqueue_pair_drain(struct taskqueue *queue, struct task_pair *tp); int taskqueue_enqueue(struct taskqueue *queue, struct task *task); +int taskqueue_stop(struct taskqueue *queue, struct task *task); void taskqueue_drain(struct taskqueue *queue, struct task *task); void taskqueue_free(struct taskqueue *queue); void taskqueue_run(struct taskqueue *queue); @@ -78,6 +82,15 @@ } while (0) /* + * Initialise a task pair structure. + */ +#define TASK_PAIR_INIT(tp, func, context) do { \ + TASK_INIT(&(tp)->tp_task[0], 0, func, context); \ + TASK_INIT(&(tp)->tp_task[1], 0, func, context); \ + (tp)->tp_last = 0; \ +} while (0) + +/* * Declare a reference to a taskqueue. */ #define TASKQUEUE_DECLARE(name) \ --Boundary-00=_O1E1M5DxgzaX2zh--