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 27677b542eSDavid E. O'Brien #include <sys/cdefs.h> 28677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 29677b542eSDavid E. O'Brien 30ca2e0534SDoug Rabson #include <sys/param.h> 31ca2e0534SDoug Rabson #include <sys/systm.h> 321de1c550SJohn Baldwin #include <sys/bus.h> 33282873e2SJohn Baldwin #include <sys/interrupt.h> 34ca2e0534SDoug Rabson #include <sys/kernel.h> 35eb5b0e05SJohn Baldwin #include <sys/kthread.h> 361de1c550SJohn Baldwin #include <sys/lock.h> 37ca2e0534SDoug Rabson #include <sys/malloc.h> 381de1c550SJohn Baldwin #include <sys/mutex.h> 391de1c550SJohn Baldwin #include <sys/taskqueue.h> 40cb32189eSKenneth D. Merry #include <sys/unistd.h> 41ca2e0534SDoug Rabson 42959b7375SPoul-Henning Kamp static MALLOC_DEFINE(M_TASKQUEUE, "taskqueue", "Task Queues"); 437874f606SScott Long static void *taskqueue_giant_ih; 44eb5b0e05SJohn Baldwin static void *taskqueue_ih; 45eb5b0e05SJohn Baldwin static STAILQ_HEAD(taskqueue_list, taskqueue) taskqueue_queues; 461de1c550SJohn Baldwin static struct mtx taskqueue_queues_mutex; 47cb32189eSKenneth D. Merry static struct proc *taskqueue_thread_proc; 488088699fSJohn Baldwin 49ca2e0534SDoug Rabson struct taskqueue { 50ca2e0534SDoug Rabson STAILQ_ENTRY(taskqueue) tq_link; 51ca2e0534SDoug Rabson STAILQ_HEAD(, task) tq_queue; 52ca2e0534SDoug Rabson const char *tq_name; 53ca2e0534SDoug Rabson taskqueue_enqueue_fn tq_enqueue; 54ca2e0534SDoug Rabson void *tq_context; 55ca2e0534SDoug Rabson int tq_draining; 561de1c550SJohn Baldwin struct mtx tq_mutex; 57ca2e0534SDoug Rabson }; 58ca2e0534SDoug Rabson 591de1c550SJohn Baldwin static void init_taskqueue_list(void *data); 601de1c550SJohn Baldwin 611de1c550SJohn Baldwin static void 621de1c550SJohn Baldwin init_taskqueue_list(void *data __unused) 631de1c550SJohn Baldwin { 641de1c550SJohn Baldwin 656008862bSJohn Baldwin mtx_init(&taskqueue_queues_mutex, "taskqueue list", NULL, MTX_DEF); 661de1c550SJohn Baldwin STAILQ_INIT(&taskqueue_queues); 671de1c550SJohn Baldwin } 681de1c550SJohn Baldwin SYSINIT(taskqueue_list, SI_SUB_INTRINSIC, SI_ORDER_ANY, init_taskqueue_list, 691de1c550SJohn Baldwin NULL); 701de1c550SJohn Baldwin 71ca2e0534SDoug Rabson struct taskqueue * 72ca2e0534SDoug Rabson taskqueue_create(const char *name, int mflags, 73ca2e0534SDoug Rabson taskqueue_enqueue_fn enqueue, void *context) 74ca2e0534SDoug Rabson { 75ca2e0534SDoug Rabson struct taskqueue *queue; 76ca2e0534SDoug Rabson 771de1c550SJohn Baldwin queue = malloc(sizeof(struct taskqueue), M_TASKQUEUE, mflags | M_ZERO); 78ca2e0534SDoug Rabson if (!queue) 79ca2e0534SDoug Rabson return 0; 801de1c550SJohn Baldwin 81ca2e0534SDoug Rabson STAILQ_INIT(&queue->tq_queue); 82ca2e0534SDoug Rabson queue->tq_name = name; 83ca2e0534SDoug Rabson queue->tq_enqueue = enqueue; 84ca2e0534SDoug Rabson queue->tq_context = context; 85ca2e0534SDoug Rabson queue->tq_draining = 0; 866008862bSJohn Baldwin mtx_init(&queue->tq_mutex, "taskqueue", NULL, MTX_DEF); 87ca2e0534SDoug Rabson 881de1c550SJohn Baldwin mtx_lock(&taskqueue_queues_mutex); 89ca2e0534SDoug Rabson STAILQ_INSERT_TAIL(&taskqueue_queues, queue, tq_link); 901de1c550SJohn Baldwin mtx_unlock(&taskqueue_queues_mutex); 91ca2e0534SDoug Rabson 92ca2e0534SDoug Rabson return queue; 93ca2e0534SDoug Rabson } 94ca2e0534SDoug Rabson 95ca2e0534SDoug Rabson void 96ca2e0534SDoug Rabson taskqueue_free(struct taskqueue *queue) 97ca2e0534SDoug Rabson { 981de1c550SJohn Baldwin 991de1c550SJohn Baldwin mtx_lock(&queue->tq_mutex); 100fbd140c7SJohn Baldwin KASSERT(queue->tq_draining == 0, ("free'ing a draining taskqueue")); 101ca2e0534SDoug Rabson queue->tq_draining = 1; 1021de1c550SJohn Baldwin mtx_unlock(&queue->tq_mutex); 103ca2e0534SDoug Rabson 104ca2e0534SDoug Rabson taskqueue_run(queue); 105ca2e0534SDoug Rabson 1061de1c550SJohn Baldwin mtx_lock(&taskqueue_queues_mutex); 107ca2e0534SDoug Rabson STAILQ_REMOVE(&taskqueue_queues, queue, taskqueue, tq_link); 1081de1c550SJohn Baldwin mtx_unlock(&taskqueue_queues_mutex); 109ca2e0534SDoug Rabson 1101de1c550SJohn Baldwin mtx_destroy(&queue->tq_mutex); 111ca2e0534SDoug Rabson free(queue, M_TASKQUEUE); 112ca2e0534SDoug Rabson } 113ca2e0534SDoug Rabson 1141de1c550SJohn Baldwin /* 1151de1c550SJohn Baldwin * Returns with the taskqueue locked. 1161de1c550SJohn Baldwin */ 117ca2e0534SDoug Rabson struct taskqueue * 118ca2e0534SDoug Rabson taskqueue_find(const char *name) 119ca2e0534SDoug Rabson { 120ca2e0534SDoug Rabson struct taskqueue *queue; 121ca2e0534SDoug Rabson 1221de1c550SJohn Baldwin mtx_lock(&taskqueue_queues_mutex); 1231de1c550SJohn Baldwin STAILQ_FOREACH(queue, &taskqueue_queues, tq_link) { 1241de1c550SJohn Baldwin mtx_lock(&queue->tq_mutex); 125eb5b0e05SJohn Baldwin if (strcmp(queue->tq_name, name) == 0) { 1261de1c550SJohn Baldwin mtx_unlock(&taskqueue_queues_mutex); 127ca2e0534SDoug Rabson return queue; 128ca2e0534SDoug Rabson } 1291de1c550SJohn Baldwin mtx_unlock(&queue->tq_mutex); 1301de1c550SJohn Baldwin } 1311de1c550SJohn Baldwin mtx_unlock(&taskqueue_queues_mutex); 132eb5b0e05SJohn Baldwin return NULL; 133ca2e0534SDoug Rabson } 134ca2e0534SDoug Rabson 135ca2e0534SDoug Rabson int 136ca2e0534SDoug Rabson taskqueue_enqueue(struct taskqueue *queue, struct task *task) 137ca2e0534SDoug Rabson { 138ca2e0534SDoug Rabson struct task *ins; 139ca2e0534SDoug Rabson struct task *prev; 140ca2e0534SDoug Rabson 141282873e2SJohn Baldwin mtx_lock(&queue->tq_mutex); 142282873e2SJohn Baldwin 143ca2e0534SDoug Rabson /* 144ca2e0534SDoug Rabson * Don't allow new tasks on a queue which is being freed. 145ca2e0534SDoug Rabson */ 146ca2e0534SDoug Rabson if (queue->tq_draining) { 1471de1c550SJohn Baldwin mtx_unlock(&queue->tq_mutex); 148ca2e0534SDoug Rabson return EPIPE; 149ca2e0534SDoug Rabson } 150ca2e0534SDoug Rabson 151ca2e0534SDoug Rabson /* 152ca2e0534SDoug Rabson * Count multiple enqueues. 153ca2e0534SDoug Rabson */ 154ca2e0534SDoug Rabson if (task->ta_pending) { 155ca2e0534SDoug Rabson task->ta_pending++; 1561de1c550SJohn Baldwin mtx_unlock(&queue->tq_mutex); 157ca2e0534SDoug Rabson return 0; 158ca2e0534SDoug Rabson } 159ca2e0534SDoug Rabson 160ca2e0534SDoug Rabson /* 161ca2e0534SDoug Rabson * Optimise the case when all tasks have the same priority. 162ca2e0534SDoug Rabson */ 16351b86781SJeffrey Hsu prev = STAILQ_LAST(&queue->tq_queue, task, ta_link); 164ca2e0534SDoug Rabson if (!prev || prev->ta_priority >= task->ta_priority) { 165ca2e0534SDoug Rabson STAILQ_INSERT_TAIL(&queue->tq_queue, task, ta_link); 166ca2e0534SDoug Rabson } else { 167ca2e0534SDoug Rabson prev = 0; 168ca2e0534SDoug Rabson for (ins = STAILQ_FIRST(&queue->tq_queue); ins; 169ca2e0534SDoug Rabson prev = ins, ins = STAILQ_NEXT(ins, ta_link)) 170ca2e0534SDoug Rabson if (ins->ta_priority < task->ta_priority) 171ca2e0534SDoug Rabson break; 172ca2e0534SDoug Rabson 173ca2e0534SDoug Rabson if (prev) 174ca2e0534SDoug Rabson STAILQ_INSERT_AFTER(&queue->tq_queue, prev, task, ta_link); 175ca2e0534SDoug Rabson else 176ca2e0534SDoug Rabson STAILQ_INSERT_HEAD(&queue->tq_queue, task, ta_link); 177ca2e0534SDoug Rabson } 178ca2e0534SDoug Rabson 179ca2e0534SDoug Rabson task->ta_pending = 1; 180ca2e0534SDoug Rabson if (queue->tq_enqueue) 181ca2e0534SDoug Rabson queue->tq_enqueue(queue->tq_context); 182282873e2SJohn Baldwin 1831de1c550SJohn Baldwin mtx_unlock(&queue->tq_mutex); 184282873e2SJohn Baldwin 185ca2e0534SDoug Rabson return 0; 186ca2e0534SDoug Rabson } 187ca2e0534SDoug Rabson 188ca2e0534SDoug Rabson void 189ca2e0534SDoug Rabson taskqueue_run(struct taskqueue *queue) 190ca2e0534SDoug Rabson { 191ca2e0534SDoug Rabson struct task *task; 192ca2e0534SDoug Rabson int pending; 193ca2e0534SDoug Rabson 1941de1c550SJohn Baldwin mtx_lock(&queue->tq_mutex); 195ca2e0534SDoug Rabson while (STAILQ_FIRST(&queue->tq_queue)) { 196ca2e0534SDoug Rabson /* 197ca2e0534SDoug Rabson * Carefully remove the first task from the queue and 198ca2e0534SDoug Rabson * zero its pending count. 199ca2e0534SDoug Rabson */ 200ca2e0534SDoug Rabson task = STAILQ_FIRST(&queue->tq_queue); 201ca2e0534SDoug Rabson STAILQ_REMOVE_HEAD(&queue->tq_queue, ta_link); 202ca2e0534SDoug Rabson pending = task->ta_pending; 203ca2e0534SDoug Rabson task->ta_pending = 0; 204282873e2SJohn Baldwin mtx_unlock(&queue->tq_mutex); 205ca2e0534SDoug Rabson 206282873e2SJohn Baldwin task->ta_func(task->ta_context, pending); 207ca2e0534SDoug Rabson 2081de1c550SJohn Baldwin mtx_lock(&queue->tq_mutex); 209ca2e0534SDoug Rabson } 2101de1c550SJohn Baldwin mtx_unlock(&queue->tq_mutex); 211ca2e0534SDoug Rabson } 212ca2e0534SDoug Rabson 213ca2e0534SDoug Rabson static void 214ca2e0534SDoug Rabson taskqueue_swi_enqueue(void *context) 215ca2e0534SDoug Rabson { 216c86b6ff5SJohn Baldwin swi_sched(taskqueue_ih, 0); 217ca2e0534SDoug Rabson } 218ca2e0534SDoug Rabson 219ca2e0534SDoug Rabson static void 2208088699fSJohn Baldwin taskqueue_swi_run(void *dummy) 221ca2e0534SDoug Rabson { 222ca2e0534SDoug Rabson taskqueue_run(taskqueue_swi); 223ca2e0534SDoug Rabson } 224ca2e0534SDoug Rabson 2257874f606SScott Long static void 2267874f606SScott Long taskqueue_swi_giant_enqueue(void *context) 2277874f606SScott Long { 2287874f606SScott Long swi_sched(taskqueue_giant_ih, 0); 2297874f606SScott Long } 2307874f606SScott Long 2317874f606SScott Long static void 2327874f606SScott Long taskqueue_swi_giant_run(void *dummy) 2337874f606SScott Long { 2347874f606SScott Long taskqueue_run(taskqueue_swi_giant); 2357874f606SScott Long } 2367874f606SScott Long 237cb32189eSKenneth D. Merry static void 238cb32189eSKenneth D. Merry taskqueue_kthread(void *arg) 239cb32189eSKenneth D. Merry { 240cb32189eSKenneth D. Merry struct mtx kthread_mutex; 241cb32189eSKenneth D. Merry 242cb32189eSKenneth D. Merry bzero(&kthread_mutex, sizeof(kthread_mutex)); 243cb32189eSKenneth D. Merry 244cb32189eSKenneth D. Merry mtx_init(&kthread_mutex, "taskqueue kthread", NULL, MTX_DEF); 245cb32189eSKenneth D. Merry 246cb32189eSKenneth D. Merry mtx_lock(&kthread_mutex); 247cb32189eSKenneth D. Merry 248cb32189eSKenneth D. Merry for (;;) { 249cb32189eSKenneth D. Merry mtx_unlock(&kthread_mutex); 250cb32189eSKenneth D. Merry taskqueue_run(taskqueue_thread); 251cb32189eSKenneth D. Merry mtx_lock(&kthread_mutex); 252cb32189eSKenneth D. Merry msleep(&taskqueue_thread, &kthread_mutex, PWAIT, "tqthr", 0); 253cb32189eSKenneth D. Merry } 254cb32189eSKenneth D. Merry } 255cb32189eSKenneth D. Merry 256cb32189eSKenneth D. Merry static void 257cb32189eSKenneth D. Merry taskqueue_thread_enqueue(void *context) 258cb32189eSKenneth D. Merry { 259cb32189eSKenneth D. Merry wakeup(&taskqueue_thread); 260cb32189eSKenneth D. Merry } 261cb32189eSKenneth D. Merry 262ca2e0534SDoug Rabson TASKQUEUE_DEFINE(swi, taskqueue_swi_enqueue, 0, 2637874f606SScott Long swi_add(NULL, "task queue", taskqueue_swi_run, NULL, SWI_TQ, 2647874f606SScott Long INTR_MPSAFE, &taskqueue_ih)); 2657874f606SScott Long 2667874f606SScott Long TASKQUEUE_DEFINE(swi_giant, taskqueue_swi_giant_enqueue, 0, 2677874f606SScott Long swi_add(NULL, "Giant task queue", taskqueue_swi_giant_run, 2687874f606SScott Long NULL, SWI_TQ_GIANT, 0, &taskqueue_giant_ih)); 269cb32189eSKenneth D. Merry 270cb32189eSKenneth D. Merry TASKQUEUE_DEFINE(thread, taskqueue_thread_enqueue, 0, 271cb32189eSKenneth D. Merry kthread_create(taskqueue_kthread, NULL, 272cd3c61b9SAlfred Perlstein &taskqueue_thread_proc, 0, 0, "taskqueue")); 273f82c9e70SSam Leffler 274f82c9e70SSam Leffler int 275f82c9e70SSam Leffler taskqueue_enqueue_fast(struct taskqueue *queue, struct task *task) 276f82c9e70SSam Leffler { 277f82c9e70SSam Leffler struct task *ins; 278f82c9e70SSam Leffler struct task *prev; 279f82c9e70SSam Leffler 280f82c9e70SSam Leffler mtx_lock_spin(&queue->tq_mutex); 281f82c9e70SSam Leffler 282f82c9e70SSam Leffler /* 283f82c9e70SSam Leffler * Don't allow new tasks on a queue which is being freed. 284f82c9e70SSam Leffler */ 285f82c9e70SSam Leffler if (queue->tq_draining) { 286f82c9e70SSam Leffler mtx_unlock_spin(&queue->tq_mutex); 287f82c9e70SSam Leffler return EPIPE; 288f82c9e70SSam Leffler } 289f82c9e70SSam Leffler 290f82c9e70SSam Leffler /* 291f82c9e70SSam Leffler * Count multiple enqueues. 292f82c9e70SSam Leffler */ 293f82c9e70SSam Leffler if (task->ta_pending) { 294f82c9e70SSam Leffler task->ta_pending++; 295f82c9e70SSam Leffler mtx_unlock_spin(&queue->tq_mutex); 296f82c9e70SSam Leffler return 0; 297f82c9e70SSam Leffler } 298f82c9e70SSam Leffler 299f82c9e70SSam Leffler /* 300f82c9e70SSam Leffler * Optimise the case when all tasks have the same priority. 301f82c9e70SSam Leffler */ 302f82c9e70SSam Leffler prev = STAILQ_LAST(&queue->tq_queue, task, ta_link); 303f82c9e70SSam Leffler if (!prev || prev->ta_priority >= task->ta_priority) { 304f82c9e70SSam Leffler STAILQ_INSERT_TAIL(&queue->tq_queue, task, ta_link); 305f82c9e70SSam Leffler } else { 306f82c9e70SSam Leffler prev = 0; 307f82c9e70SSam Leffler for (ins = STAILQ_FIRST(&queue->tq_queue); ins; 308f82c9e70SSam Leffler prev = ins, ins = STAILQ_NEXT(ins, ta_link)) 309f82c9e70SSam Leffler if (ins->ta_priority < task->ta_priority) 310f82c9e70SSam Leffler break; 311f82c9e70SSam Leffler 312f82c9e70SSam Leffler if (prev) 313f82c9e70SSam Leffler STAILQ_INSERT_AFTER(&queue->tq_queue, prev, task, ta_link); 314f82c9e70SSam Leffler else 315f82c9e70SSam Leffler STAILQ_INSERT_HEAD(&queue->tq_queue, task, ta_link); 316f82c9e70SSam Leffler } 317f82c9e70SSam Leffler 318f82c9e70SSam Leffler task->ta_pending = 1; 319f82c9e70SSam Leffler if (queue->tq_enqueue) 320f82c9e70SSam Leffler queue->tq_enqueue(queue->tq_context); 321f82c9e70SSam Leffler 322f82c9e70SSam Leffler mtx_unlock_spin(&queue->tq_mutex); 323f82c9e70SSam Leffler 324f82c9e70SSam Leffler return 0; 325f82c9e70SSam Leffler } 326f82c9e70SSam Leffler 327f82c9e70SSam Leffler static void 328f82c9e70SSam Leffler taskqueue_run_fast(struct taskqueue *queue) 329f82c9e70SSam Leffler { 330f82c9e70SSam Leffler struct task *task; 331f82c9e70SSam Leffler int pending; 332f82c9e70SSam Leffler 333f82c9e70SSam Leffler mtx_lock_spin(&queue->tq_mutex); 334f82c9e70SSam Leffler while (STAILQ_FIRST(&queue->tq_queue)) { 335f82c9e70SSam Leffler /* 336f82c9e70SSam Leffler * Carefully remove the first task from the queue and 337f82c9e70SSam Leffler * zero its pending count. 338f82c9e70SSam Leffler */ 339f82c9e70SSam Leffler task = STAILQ_FIRST(&queue->tq_queue); 340f82c9e70SSam Leffler STAILQ_REMOVE_HEAD(&queue->tq_queue, ta_link); 341f82c9e70SSam Leffler pending = task->ta_pending; 342f82c9e70SSam Leffler task->ta_pending = 0; 343f82c9e70SSam Leffler mtx_unlock_spin(&queue->tq_mutex); 344f82c9e70SSam Leffler 345f82c9e70SSam Leffler task->ta_func(task->ta_context, pending); 346f82c9e70SSam Leffler 347f82c9e70SSam Leffler mtx_lock_spin(&queue->tq_mutex); 348f82c9e70SSam Leffler } 349f82c9e70SSam Leffler mtx_unlock_spin(&queue->tq_mutex); 350f82c9e70SSam Leffler } 351f82c9e70SSam Leffler 352f82c9e70SSam Leffler struct taskqueue *taskqueue_fast; 353f82c9e70SSam Leffler static void *taskqueue_fast_ih; 354f82c9e70SSam Leffler 355f82c9e70SSam Leffler static void 356f82c9e70SSam Leffler taskqueue_fast_schedule(void *context) 357f82c9e70SSam Leffler { 358f82c9e70SSam Leffler swi_sched(taskqueue_fast_ih, 0); 359f82c9e70SSam Leffler } 360f82c9e70SSam Leffler 361f82c9e70SSam Leffler static void 362f82c9e70SSam Leffler taskqueue_fast_run(void *dummy) 363f82c9e70SSam Leffler { 364f82c9e70SSam Leffler taskqueue_run_fast(taskqueue_fast); 365f82c9e70SSam Leffler } 366f82c9e70SSam Leffler 367f82c9e70SSam Leffler static void 368f82c9e70SSam Leffler taskqueue_define_fast(void *arg) 369f82c9e70SSam Leffler { 370f82c9e70SSam Leffler taskqueue_fast = malloc(sizeof(struct taskqueue), 371f82c9e70SSam Leffler M_TASKQUEUE, M_NOWAIT | M_ZERO); 372f82c9e70SSam Leffler if (!taskqueue_fast) { 373f82c9e70SSam Leffler printf("%s: Unable to allocate fast task queue!\n", __func__); 374f82c9e70SSam Leffler return; 375f82c9e70SSam Leffler } 376f82c9e70SSam Leffler 377f82c9e70SSam Leffler STAILQ_INIT(&taskqueue_fast->tq_queue); 378f82c9e70SSam Leffler taskqueue_fast->tq_name = "fast"; 379f82c9e70SSam Leffler taskqueue_fast->tq_enqueue = taskqueue_fast_schedule; 3807e2282a5SSam Leffler mtx_init(&taskqueue_fast->tq_mutex, "taskqueue_fast", NULL, MTX_SPIN); 381f82c9e70SSam Leffler 382f82c9e70SSam Leffler mtx_lock(&taskqueue_queues_mutex); 383f82c9e70SSam Leffler STAILQ_INSERT_TAIL(&taskqueue_queues, taskqueue_fast, tq_link); 384f82c9e70SSam Leffler mtx_unlock(&taskqueue_queues_mutex); 385f82c9e70SSam Leffler 386f82c9e70SSam Leffler swi_add(NULL, "Fast task queue", taskqueue_fast_run, 387f82c9e70SSam Leffler NULL, SWI_TQ_FAST, 0, &taskqueue_fast_ih); 388f82c9e70SSam Leffler } 389f82c9e70SSam Leffler SYSINIT(taskqueue_fast, SI_SUB_CONFIGURE, SI_ORDER_SECOND, 390f82c9e70SSam Leffler taskqueue_define_fast, NULL); 391