1ca2e0534SDoug Rabson /*- 2ca2e0534SDoug Rabson * Copyright (c) 2000 Doug Rabson 3ca2e0534SDoug Rabson * All rights reserved. 4ca2e0534SDoug Rabson * 5ca2e0534SDoug Rabson * Redistribution and use in source and binary forms, with or without 6ca2e0534SDoug Rabson * modification, are permitted provided that the following conditions 7ca2e0534SDoug Rabson * are met: 8ca2e0534SDoug Rabson * 1. Redistributions of source code must retain the above copyright 9ca2e0534SDoug Rabson * notice, this list of conditions and the following disclaimer. 10ca2e0534SDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright 11ca2e0534SDoug Rabson * notice, this list of conditions and the following disclaimer in the 12ca2e0534SDoug Rabson * documentation and/or other materials provided with the distribution. 13ca2e0534SDoug Rabson * 14ca2e0534SDoug Rabson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15ca2e0534SDoug Rabson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16ca2e0534SDoug Rabson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17ca2e0534SDoug Rabson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18ca2e0534SDoug Rabson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19ca2e0534SDoug Rabson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20ca2e0534SDoug Rabson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21ca2e0534SDoug Rabson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22ca2e0534SDoug Rabson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23ca2e0534SDoug Rabson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24ca2e0534SDoug Rabson * SUCH DAMAGE. 25ca2e0534SDoug Rabson * 26ca2e0534SDoug Rabson * $FreeBSD$ 27ca2e0534SDoug Rabson */ 28ca2e0534SDoug Rabson 29ca2e0534SDoug Rabson #include <sys/param.h> 30ca2e0534SDoug Rabson #include <sys/queue.h> 31ca2e0534SDoug Rabson #include <sys/systm.h> 32ca2e0534SDoug Rabson #include <sys/kernel.h> 33ca2e0534SDoug Rabson #include <sys/taskqueue.h> 34ca2e0534SDoug Rabson #include <sys/interrupt.h> 35ca2e0534SDoug Rabson #include <sys/malloc.h> 36ca2e0534SDoug Rabson #include <machine/ipl.h> 37ca2e0534SDoug Rabson 38ca2e0534SDoug Rabson MALLOC_DEFINE(M_TASKQUEUE, "taskqueue", "Task Queues"); 39ca2e0534SDoug Rabson 40ca2e0534SDoug Rabson static STAILQ_HEAD(taskqueue_list, taskqueue) taskqueue_queues; 41ca2e0534SDoug Rabson 42ca2e0534SDoug Rabson struct taskqueue { 43ca2e0534SDoug Rabson STAILQ_ENTRY(taskqueue) tq_link; 44ca2e0534SDoug Rabson STAILQ_HEAD(, task) tq_queue; 45ca2e0534SDoug Rabson const char *tq_name; 46ca2e0534SDoug Rabson taskqueue_enqueue_fn tq_enqueue; 47ca2e0534SDoug Rabson void *tq_context; 48ca2e0534SDoug Rabson int tq_draining; 49ca2e0534SDoug Rabson }; 50ca2e0534SDoug Rabson 51ca2e0534SDoug Rabson struct taskqueue * 52ca2e0534SDoug Rabson taskqueue_create(const char *name, int mflags, 53ca2e0534SDoug Rabson taskqueue_enqueue_fn enqueue, void *context) 54ca2e0534SDoug Rabson { 55ca2e0534SDoug Rabson struct taskqueue *queue; 56ca2e0534SDoug Rabson static int once = 1; 57ca2e0534SDoug Rabson int s; 58ca2e0534SDoug Rabson 59ca2e0534SDoug Rabson queue = malloc(sizeof(struct taskqueue), M_TASKQUEUE, mflags); 60ca2e0534SDoug Rabson if (!queue) 61ca2e0534SDoug Rabson return 0; 62ca2e0534SDoug Rabson STAILQ_INIT(&queue->tq_queue); 63ca2e0534SDoug Rabson queue->tq_name = name; 64ca2e0534SDoug Rabson queue->tq_enqueue = enqueue; 65ca2e0534SDoug Rabson queue->tq_context = context; 66ca2e0534SDoug Rabson queue->tq_draining = 0; 67ca2e0534SDoug Rabson 68ca2e0534SDoug Rabson s = splhigh(); 69ca2e0534SDoug Rabson if (once) { 70ca2e0534SDoug Rabson STAILQ_INIT(&taskqueue_queues); 71ca2e0534SDoug Rabson once = 0; 72ca2e0534SDoug Rabson } 73ca2e0534SDoug Rabson STAILQ_INSERT_TAIL(&taskqueue_queues, queue, tq_link); 74ca2e0534SDoug Rabson splx(s); 75ca2e0534SDoug Rabson 76ca2e0534SDoug Rabson return queue; 77ca2e0534SDoug Rabson } 78ca2e0534SDoug Rabson 79ca2e0534SDoug Rabson void 80ca2e0534SDoug Rabson taskqueue_free(struct taskqueue *queue) 81ca2e0534SDoug Rabson { 82ca2e0534SDoug Rabson int s = splhigh(); 83ca2e0534SDoug Rabson queue->tq_draining = 1; 84ca2e0534SDoug Rabson splx(s); 85ca2e0534SDoug Rabson 86ca2e0534SDoug Rabson taskqueue_run(queue); 87ca2e0534SDoug Rabson 88ca2e0534SDoug Rabson s = splhigh(); 89ca2e0534SDoug Rabson STAILQ_REMOVE(&taskqueue_queues, queue, taskqueue, tq_link); 90ca2e0534SDoug Rabson splx(s); 91ca2e0534SDoug Rabson 92ca2e0534SDoug Rabson free(queue, M_TASKQUEUE); 93ca2e0534SDoug Rabson } 94ca2e0534SDoug Rabson 95ca2e0534SDoug Rabson struct taskqueue * 96ca2e0534SDoug Rabson taskqueue_find(const char *name) 97ca2e0534SDoug Rabson { 98ca2e0534SDoug Rabson struct taskqueue *queue; 99ca2e0534SDoug Rabson int s; 100ca2e0534SDoug Rabson 101ca2e0534SDoug Rabson s = splhigh(); 102ca2e0534SDoug Rabson STAILQ_FOREACH(queue, &taskqueue_queues, tq_link) 103ca2e0534SDoug Rabson if (!strcmp(queue->tq_name, name)) { 104ca2e0534SDoug Rabson splx(s); 105ca2e0534SDoug Rabson return queue; 106ca2e0534SDoug Rabson } 107ca2e0534SDoug Rabson splx(s); 108ca2e0534SDoug Rabson return 0; 109ca2e0534SDoug Rabson } 110ca2e0534SDoug Rabson 111ca2e0534SDoug Rabson int 112ca2e0534SDoug Rabson taskqueue_enqueue(struct taskqueue *queue, struct task *task) 113ca2e0534SDoug Rabson { 114ca2e0534SDoug Rabson struct task *ins; 115ca2e0534SDoug Rabson struct task *prev; 116ca2e0534SDoug Rabson 117ca2e0534SDoug Rabson int s = splhigh(); 118ca2e0534SDoug Rabson 119ca2e0534SDoug Rabson /* 120ca2e0534SDoug Rabson * Don't allow new tasks on a queue which is being freed. 121ca2e0534SDoug Rabson */ 122ca2e0534SDoug Rabson if (queue->tq_draining) { 123ca2e0534SDoug Rabson splx(s); 124ca2e0534SDoug Rabson return EPIPE; 125ca2e0534SDoug Rabson } 126ca2e0534SDoug Rabson 127ca2e0534SDoug Rabson /* 128ca2e0534SDoug Rabson * Count multiple enqueues. 129ca2e0534SDoug Rabson */ 130ca2e0534SDoug Rabson if (task->ta_pending) { 131ca2e0534SDoug Rabson task->ta_pending++; 132ca2e0534SDoug Rabson splx(s); 133ca2e0534SDoug Rabson return 0; 134ca2e0534SDoug Rabson } 135ca2e0534SDoug Rabson 136ca2e0534SDoug Rabson /* 137ca2e0534SDoug Rabson * Optimise the case when all tasks have the same priority. 138ca2e0534SDoug Rabson */ 139ca2e0534SDoug Rabson prev = STAILQ_LAST(&queue->tq_queue); 140ca2e0534SDoug Rabson if (!prev || prev->ta_priority >= task->ta_priority) { 141ca2e0534SDoug Rabson STAILQ_INSERT_TAIL(&queue->tq_queue, task, ta_link); 142ca2e0534SDoug Rabson } else { 143ca2e0534SDoug Rabson prev = 0; 144ca2e0534SDoug Rabson for (ins = STAILQ_FIRST(&queue->tq_queue); ins; 145ca2e0534SDoug Rabson prev = ins, ins = STAILQ_NEXT(ins, ta_link)) 146ca2e0534SDoug Rabson if (ins->ta_priority < task->ta_priority) 147ca2e0534SDoug Rabson break; 148ca2e0534SDoug Rabson 149ca2e0534SDoug Rabson if (prev) 150ca2e0534SDoug Rabson STAILQ_INSERT_AFTER(&queue->tq_queue, prev, task, ta_link); 151ca2e0534SDoug Rabson else 152ca2e0534SDoug Rabson STAILQ_INSERT_HEAD(&queue->tq_queue, task, ta_link); 153ca2e0534SDoug Rabson } 154ca2e0534SDoug Rabson 155ca2e0534SDoug Rabson task->ta_pending = 1; 156ca2e0534SDoug Rabson if (queue->tq_enqueue) 157ca2e0534SDoug Rabson queue->tq_enqueue(queue->tq_context); 158ca2e0534SDoug Rabson 159ca2e0534SDoug Rabson splx(s); 160ca2e0534SDoug Rabson 161ca2e0534SDoug Rabson return 0; 162ca2e0534SDoug Rabson } 163ca2e0534SDoug Rabson 164ca2e0534SDoug Rabson void 165ca2e0534SDoug Rabson taskqueue_run(struct taskqueue *queue) 166ca2e0534SDoug Rabson { 167ca2e0534SDoug Rabson int s; 168ca2e0534SDoug Rabson struct task *task; 169ca2e0534SDoug Rabson int pending; 170ca2e0534SDoug Rabson 171ca2e0534SDoug Rabson s = splhigh(); 172ca2e0534SDoug Rabson while (STAILQ_FIRST(&queue->tq_queue)) { 173ca2e0534SDoug Rabson /* 174ca2e0534SDoug Rabson * Carefully remove the first task from the queue and 175ca2e0534SDoug Rabson * zero its pending count. 176ca2e0534SDoug Rabson */ 177ca2e0534SDoug Rabson task = STAILQ_FIRST(&queue->tq_queue); 178ca2e0534SDoug Rabson STAILQ_REMOVE_HEAD(&queue->tq_queue, ta_link); 179ca2e0534SDoug Rabson pending = task->ta_pending; 180ca2e0534SDoug Rabson task->ta_pending = 0; 181ca2e0534SDoug Rabson splx(s); 182ca2e0534SDoug Rabson 183ca2e0534SDoug Rabson task->ta_func(task->ta_context, pending); 184ca2e0534SDoug Rabson 185ca2e0534SDoug Rabson s = splhigh(); 186ca2e0534SDoug Rabson } 187ca2e0534SDoug Rabson splx(s); 188ca2e0534SDoug Rabson } 189ca2e0534SDoug Rabson 190ca2e0534SDoug Rabson static void 191ca2e0534SDoug Rabson taskqueue_swi_enqueue(void *context) 192ca2e0534SDoug Rabson { 193ca2e0534SDoug Rabson setsofttq(); 194ca2e0534SDoug Rabson } 195ca2e0534SDoug Rabson 196ca2e0534SDoug Rabson static void 197ca2e0534SDoug Rabson taskqueue_swi_run(void) 198ca2e0534SDoug Rabson { 199ca2e0534SDoug Rabson taskqueue_run(taskqueue_swi); 200ca2e0534SDoug Rabson } 201ca2e0534SDoug Rabson 202ca2e0534SDoug Rabson TASKQUEUE_DEFINE(swi, taskqueue_swi_enqueue, 0, 203ca2e0534SDoug Rabson register_swi(SWI_TQ, taskqueue_swi_run)); 204