1eda14cbcSMatt Macy /* 2eda14cbcSMatt Macy * Copyright (c) 2009 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3eda14cbcSMatt Macy * All rights reserved. 4eda14cbcSMatt Macy * 5eda14cbcSMatt Macy * Copyright (c) 2012 Spectra Logic Corporation. All rights reserved. 6eda14cbcSMatt Macy * 7eda14cbcSMatt Macy * Redistribution and use in source and binary forms, with or without 8eda14cbcSMatt Macy * modification, are permitted provided that the following conditions 9eda14cbcSMatt Macy * are met: 10eda14cbcSMatt Macy * 1. Redistributions of source code must retain the above copyright 11eda14cbcSMatt Macy * notice, this list of conditions and the following disclaimer. 12eda14cbcSMatt Macy * 2. Redistributions in binary form must reproduce the above copyright 13eda14cbcSMatt Macy * notice, this list of conditions and the following disclaimer in the 14eda14cbcSMatt Macy * documentation and/or other materials provided with the distribution. 15eda14cbcSMatt Macy * 16eda14cbcSMatt Macy * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 17eda14cbcSMatt Macy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18eda14cbcSMatt Macy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19eda14cbcSMatt Macy * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 20eda14cbcSMatt Macy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21eda14cbcSMatt Macy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22eda14cbcSMatt Macy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23eda14cbcSMatt Macy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24eda14cbcSMatt Macy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25eda14cbcSMatt Macy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26eda14cbcSMatt Macy * SUCH DAMAGE. 27eda14cbcSMatt Macy */ 28eda14cbcSMatt Macy 29eda14cbcSMatt Macy #include <sys/param.h> 30eda14cbcSMatt Macy #include <sys/kernel.h> 31eda14cbcSMatt Macy #include <sys/kmem.h> 32eda14cbcSMatt Macy #include <sys/lock.h> 33eda14cbcSMatt Macy #include <sys/mutex.h> 34eda14cbcSMatt Macy #include <sys/queue.h> 35eda14cbcSMatt Macy #include <sys/taskq.h> 36180f8225SMatt Macy #include <sys/taskqueue.h> 37eda14cbcSMatt Macy #include <sys/zfs_context.h> 38180f8225SMatt Macy 39180f8225SMatt Macy #if defined(__i386__) || defined(__amd64__) || defined(__aarch64__) 40180f8225SMatt Macy #include <machine/pcb.h> 41180f8225SMatt Macy #endif 42eda14cbcSMatt Macy 43eda14cbcSMatt Macy #include <vm/uma.h> 44eda14cbcSMatt Macy 45eda14cbcSMatt Macy static uint_t taskq_tsd; 46eda14cbcSMatt Macy static uma_zone_t taskq_zone; 47eda14cbcSMatt Macy 48681ce946SMartin Matuska /* 49681ce946SMartin Matuska * Global system-wide dynamic task queue available for all consumers. This 50681ce946SMartin Matuska * taskq is not intended for long-running tasks; instead, a dedicated taskq 51681ce946SMartin Matuska * should be created. 52681ce946SMartin Matuska */ 53eda14cbcSMatt Macy taskq_t *system_taskq = NULL; 54eda14cbcSMatt Macy taskq_t *system_delay_taskq = NULL; 55eda14cbcSMatt Macy taskq_t *dynamic_taskq = NULL; 56eda14cbcSMatt Macy 57eda14cbcSMatt Macy proc_t *system_proc; 58eda14cbcSMatt Macy 59eda14cbcSMatt Macy static MALLOC_DEFINE(M_TASKQ, "taskq", "taskq structures"); 60eda14cbcSMatt Macy 6122b267e8SMartin Matuska static LIST_HEAD(tqenthashhead, taskq_ent) *tqenthashtbl; 62eda14cbcSMatt Macy static unsigned long tqenthash; 63eda14cbcSMatt Macy static unsigned long tqenthashlock; 64eda14cbcSMatt Macy static struct sx *tqenthashtbl_lock; 65eda14cbcSMatt Macy 66c3f8f86eSMateusz Guzik static taskqid_t tqidnext; 67eda14cbcSMatt Macy 68eda14cbcSMatt Macy #define TQIDHASH(tqid) (&tqenthashtbl[(tqid) & tqenthash]) 69eda14cbcSMatt Macy #define TQIDHASHLOCK(tqid) (&tqenthashtbl_lock[((tqid) & tqenthashlock)]) 70eda14cbcSMatt Macy 7122b267e8SMartin Matuska #define NORMAL_TASK 0 72eda14cbcSMatt Macy #define TIMEOUT_TASK 1 73eda14cbcSMatt Macy 74eda14cbcSMatt Macy static void 75eda14cbcSMatt Macy system_taskq_init(void *arg) 76eda14cbcSMatt Macy { 77eda14cbcSMatt Macy int i; 78eda14cbcSMatt Macy 79eda14cbcSMatt Macy tsd_create(&taskq_tsd, NULL); 80eda14cbcSMatt Macy tqenthashtbl = hashinit(mp_ncpus * 8, M_TASKQ, &tqenthash); 81eda14cbcSMatt Macy tqenthashlock = (tqenthash + 1) / 8; 82eda14cbcSMatt Macy if (tqenthashlock > 0) 83eda14cbcSMatt Macy tqenthashlock--; 84eda14cbcSMatt Macy tqenthashtbl_lock = 85eda14cbcSMatt Macy malloc(sizeof (*tqenthashtbl_lock) * (tqenthashlock + 1), 86eda14cbcSMatt Macy M_TASKQ, M_WAITOK | M_ZERO); 87eda14cbcSMatt Macy for (i = 0; i < tqenthashlock + 1; i++) 88eda14cbcSMatt Macy sx_init_flags(&tqenthashtbl_lock[i], "tqenthash", SX_DUPOK); 89eda14cbcSMatt Macy taskq_zone = uma_zcreate("taskq_zone", sizeof (taskq_ent_t), 90eda14cbcSMatt Macy NULL, NULL, NULL, NULL, 91eda14cbcSMatt Macy UMA_ALIGN_CACHE, 0); 92eda14cbcSMatt Macy system_taskq = taskq_create("system_taskq", mp_ncpus, minclsyspri, 93eda14cbcSMatt Macy 0, 0, 0); 94eda14cbcSMatt Macy system_delay_taskq = taskq_create("system_delay_taskq", mp_ncpus, 95eda14cbcSMatt Macy minclsyspri, 0, 0, 0); 96eda14cbcSMatt Macy } 97eda14cbcSMatt Macy SYSINIT(system_taskq_init, SI_SUB_CONFIGURE, SI_ORDER_ANY, system_taskq_init, 98eda14cbcSMatt Macy NULL); 99eda14cbcSMatt Macy 100eda14cbcSMatt Macy static void 101eda14cbcSMatt Macy system_taskq_fini(void *arg) 102eda14cbcSMatt Macy { 103eda14cbcSMatt Macy int i; 104eda14cbcSMatt Macy 105eda14cbcSMatt Macy taskq_destroy(system_delay_taskq); 106eda14cbcSMatt Macy taskq_destroy(system_taskq); 107eda14cbcSMatt Macy uma_zdestroy(taskq_zone); 108eda14cbcSMatt Macy tsd_destroy(&taskq_tsd); 109eda14cbcSMatt Macy for (i = 0; i < tqenthashlock + 1; i++) 110eda14cbcSMatt Macy sx_destroy(&tqenthashtbl_lock[i]); 111eda14cbcSMatt Macy for (i = 0; i < tqenthash + 1; i++) 11222b267e8SMartin Matuska VERIFY(LIST_EMPTY(&tqenthashtbl[i])); 113eda14cbcSMatt Macy free(tqenthashtbl_lock, M_TASKQ); 114eda14cbcSMatt Macy free(tqenthashtbl, M_TASKQ); 115eda14cbcSMatt Macy } 116eda14cbcSMatt Macy SYSUNINIT(system_taskq_fini, SI_SUB_CONFIGURE, SI_ORDER_ANY, system_taskq_fini, 117eda14cbcSMatt Macy NULL); 118eda14cbcSMatt Macy 119c3f8f86eSMateusz Guzik #ifdef __LP64__ 120c3f8f86eSMateusz Guzik static taskqid_t 121c3f8f86eSMateusz Guzik __taskq_genid(void) 122c3f8f86eSMateusz Guzik { 123180f8225SMatt Macy taskqid_t tqid; 124c3f8f86eSMateusz Guzik 125180f8225SMatt Macy /* 126180f8225SMatt Macy * Assume a 64-bit counter will not wrap in practice. 127180f8225SMatt Macy */ 128180f8225SMatt Macy tqid = atomic_add_64_nv(&tqidnext, 1); 129180f8225SMatt Macy VERIFY(tqid); 130180f8225SMatt Macy return (tqid); 131c3f8f86eSMateusz Guzik } 132c3f8f86eSMateusz Guzik #else 133c3f8f86eSMateusz Guzik static taskqid_t 134c3f8f86eSMateusz Guzik __taskq_genid(void) 135c3f8f86eSMateusz Guzik { 136c3f8f86eSMateusz Guzik taskqid_t tqid; 137c3f8f86eSMateusz Guzik 138c3f8f86eSMateusz Guzik for (;;) { 139180f8225SMatt Macy tqid = atomic_add_32_nv(&tqidnext, 1); 140c3f8f86eSMateusz Guzik if (__predict_true(tqid != 0)) 141c3f8f86eSMateusz Guzik break; 142c3f8f86eSMateusz Guzik } 143180f8225SMatt Macy VERIFY(tqid); 144c3f8f86eSMateusz Guzik return (tqid); 145c3f8f86eSMateusz Guzik } 146c3f8f86eSMateusz Guzik #endif 147c3f8f86eSMateusz Guzik 148eda14cbcSMatt Macy static taskq_ent_t * 149eda14cbcSMatt Macy taskq_lookup(taskqid_t tqid) 150eda14cbcSMatt Macy { 151eda14cbcSMatt Macy taskq_ent_t *ent = NULL; 152eda14cbcSMatt Macy 15322b267e8SMartin Matuska if (tqid == 0) 15422b267e8SMartin Matuska return (NULL); 15522b267e8SMartin Matuska sx_slock(TQIDHASHLOCK(tqid)); 15622b267e8SMartin Matuska LIST_FOREACH(ent, TQIDHASH(tqid), tqent_hash) { 157eda14cbcSMatt Macy if (ent->tqent_id == tqid) 158eda14cbcSMatt Macy break; 159eda14cbcSMatt Macy } 160eda14cbcSMatt Macy if (ent != NULL) 161eda14cbcSMatt Macy refcount_acquire(&ent->tqent_rc); 16222b267e8SMartin Matuska sx_sunlock(TQIDHASHLOCK(tqid)); 163eda14cbcSMatt Macy return (ent); 164eda14cbcSMatt Macy } 165eda14cbcSMatt Macy 166eda14cbcSMatt Macy static taskqid_t 167eda14cbcSMatt Macy taskq_insert(taskq_ent_t *ent) 168eda14cbcSMatt Macy { 16922b267e8SMartin Matuska taskqid_t tqid = __taskq_genid(); 170eda14cbcSMatt Macy 171eda14cbcSMatt Macy ent->tqent_id = tqid; 172eda14cbcSMatt Macy sx_xlock(TQIDHASHLOCK(tqid)); 17322b267e8SMartin Matuska LIST_INSERT_HEAD(TQIDHASH(tqid), ent, tqent_hash); 174eda14cbcSMatt Macy sx_xunlock(TQIDHASHLOCK(tqid)); 175eda14cbcSMatt Macy return (tqid); 176eda14cbcSMatt Macy } 177eda14cbcSMatt Macy 178eda14cbcSMatt Macy static void 179eda14cbcSMatt Macy taskq_remove(taskq_ent_t *ent) 180eda14cbcSMatt Macy { 181eda14cbcSMatt Macy taskqid_t tqid = ent->tqent_id; 182eda14cbcSMatt Macy 18322b267e8SMartin Matuska if (tqid == 0) 184eda14cbcSMatt Macy return; 185eda14cbcSMatt Macy sx_xlock(TQIDHASHLOCK(tqid)); 18622b267e8SMartin Matuska if (ent->tqent_id != 0) { 18722b267e8SMartin Matuska LIST_REMOVE(ent, tqent_hash); 18822b267e8SMartin Matuska ent->tqent_id = 0; 18922b267e8SMartin Matuska } 190eda14cbcSMatt Macy sx_xunlock(TQIDHASHLOCK(tqid)); 191eda14cbcSMatt Macy } 192eda14cbcSMatt Macy 193eda14cbcSMatt Macy static void 194eda14cbcSMatt Macy taskq_tsd_set(void *context) 195eda14cbcSMatt Macy { 196eda14cbcSMatt Macy taskq_t *tq = context; 197eda14cbcSMatt Macy 19811322826SMatt Macy #if defined(__amd64__) || defined(__aarch64__) 199c40487d4SMatt Macy if (context != NULL && tsd_get(taskq_tsd) == NULL) 200c40487d4SMatt Macy fpu_kern_thread(FPU_KERN_NORMAL); 201c40487d4SMatt Macy #endif 202eda14cbcSMatt Macy tsd_set(taskq_tsd, tq); 203eda14cbcSMatt Macy } 204eda14cbcSMatt Macy 205eda14cbcSMatt Macy static taskq_t * 206eda14cbcSMatt Macy taskq_create_impl(const char *name, int nthreads, pri_t pri, 207eda14cbcSMatt Macy proc_t *proc __maybe_unused, uint_t flags) 208eda14cbcSMatt Macy { 209eda14cbcSMatt Macy taskq_t *tq; 210eda14cbcSMatt Macy 211eda14cbcSMatt Macy if ((flags & TASKQ_THREADS_CPU_PCT) != 0) 212eda14cbcSMatt Macy nthreads = MAX((mp_ncpus * nthreads) / 100, 1); 213eda14cbcSMatt Macy 214eda14cbcSMatt Macy tq = kmem_alloc(sizeof (*tq), KM_SLEEP); 21514c2e0a0SMartin Matuska tq->tq_nthreads = nthreads; 216eda14cbcSMatt Macy tq->tq_queue = taskqueue_create(name, M_WAITOK, 217eda14cbcSMatt Macy taskqueue_thread_enqueue, &tq->tq_queue); 218eda14cbcSMatt Macy taskqueue_set_callback(tq->tq_queue, TASKQUEUE_CALLBACK_TYPE_INIT, 219eda14cbcSMatt Macy taskq_tsd_set, tq); 220eda14cbcSMatt Macy taskqueue_set_callback(tq->tq_queue, TASKQUEUE_CALLBACK_TYPE_SHUTDOWN, 221eda14cbcSMatt Macy taskq_tsd_set, NULL); 222eda14cbcSMatt Macy (void) taskqueue_start_threads_in_proc(&tq->tq_queue, nthreads, pri, 223eda14cbcSMatt Macy proc, "%s", name); 224eda14cbcSMatt Macy 225eda14cbcSMatt Macy return ((taskq_t *)tq); 226eda14cbcSMatt Macy } 227eda14cbcSMatt Macy 228eda14cbcSMatt Macy taskq_t * 229eda14cbcSMatt Macy taskq_create(const char *name, int nthreads, pri_t pri, int minalloc __unused, 230eda14cbcSMatt Macy int maxalloc __unused, uint_t flags) 231eda14cbcSMatt Macy { 232eda14cbcSMatt Macy return (taskq_create_impl(name, nthreads, pri, system_proc, flags)); 233eda14cbcSMatt Macy } 234eda14cbcSMatt Macy 235eda14cbcSMatt Macy taskq_t * 236eda14cbcSMatt Macy taskq_create_proc(const char *name, int nthreads, pri_t pri, 237eda14cbcSMatt Macy int minalloc __unused, int maxalloc __unused, proc_t *proc, uint_t flags) 238eda14cbcSMatt Macy { 239eda14cbcSMatt Macy return (taskq_create_impl(name, nthreads, pri, proc, flags)); 240eda14cbcSMatt Macy } 241eda14cbcSMatt Macy 242eda14cbcSMatt Macy void 243eda14cbcSMatt Macy taskq_destroy(taskq_t *tq) 244eda14cbcSMatt Macy { 245eda14cbcSMatt Macy 246eda14cbcSMatt Macy taskqueue_free(tq->tq_queue); 247eda14cbcSMatt Macy kmem_free(tq, sizeof (*tq)); 248eda14cbcSMatt Macy } 249eda14cbcSMatt Macy 25014c2e0a0SMartin Matuska static void taskq_sync_assign(void *arg); 25114c2e0a0SMartin Matuska 25214c2e0a0SMartin Matuska typedef struct taskq_sync_arg { 25314c2e0a0SMartin Matuska kthread_t *tqa_thread; 25414c2e0a0SMartin Matuska kcondvar_t tqa_cv; 25514c2e0a0SMartin Matuska kmutex_t tqa_lock; 25614c2e0a0SMartin Matuska int tqa_ready; 25714c2e0a0SMartin Matuska } taskq_sync_arg_t; 25814c2e0a0SMartin Matuska 25914c2e0a0SMartin Matuska static void 26014c2e0a0SMartin Matuska taskq_sync_assign(void *arg) 26114c2e0a0SMartin Matuska { 26214c2e0a0SMartin Matuska taskq_sync_arg_t *tqa = arg; 26314c2e0a0SMartin Matuska 26414c2e0a0SMartin Matuska mutex_enter(&tqa->tqa_lock); 26514c2e0a0SMartin Matuska tqa->tqa_thread = curthread; 26614c2e0a0SMartin Matuska tqa->tqa_ready = 1; 26714c2e0a0SMartin Matuska cv_signal(&tqa->tqa_cv); 26814c2e0a0SMartin Matuska while (tqa->tqa_ready == 1) 26914c2e0a0SMartin Matuska cv_wait(&tqa->tqa_cv, &tqa->tqa_lock); 27014c2e0a0SMartin Matuska mutex_exit(&tqa->tqa_lock); 27114c2e0a0SMartin Matuska } 27214c2e0a0SMartin Matuska 27314c2e0a0SMartin Matuska /* 27414c2e0a0SMartin Matuska * Create a taskq with a specified number of pool threads. Allocate 27514c2e0a0SMartin Matuska * and return an array of nthreads kthread_t pointers, one for each 27614c2e0a0SMartin Matuska * thread in the pool. The array is not ordered and must be freed 27714c2e0a0SMartin Matuska * by the caller. 27814c2e0a0SMartin Matuska */ 27914c2e0a0SMartin Matuska taskq_t * 28014c2e0a0SMartin Matuska taskq_create_synced(const char *name, int nthreads, pri_t pri, 28114c2e0a0SMartin Matuska int minalloc, int maxalloc, uint_t flags, kthread_t ***ktpp) 28214c2e0a0SMartin Matuska { 28314c2e0a0SMartin Matuska taskq_t *tq; 28414c2e0a0SMartin Matuska taskq_sync_arg_t *tqs = kmem_zalloc(sizeof (*tqs) * nthreads, KM_SLEEP); 28514c2e0a0SMartin Matuska kthread_t **kthreads = kmem_zalloc(sizeof (*kthreads) * nthreads, 28614c2e0a0SMartin Matuska KM_SLEEP); 28714c2e0a0SMartin Matuska 28814c2e0a0SMartin Matuska flags &= ~(TASKQ_DYNAMIC | TASKQ_THREADS_CPU_PCT | TASKQ_DC_BATCH); 28914c2e0a0SMartin Matuska 29014c2e0a0SMartin Matuska tq = taskq_create(name, nthreads, minclsyspri, nthreads, INT_MAX, 29114c2e0a0SMartin Matuska flags | TASKQ_PREPOPULATE); 29214c2e0a0SMartin Matuska VERIFY(tq != NULL); 29314c2e0a0SMartin Matuska VERIFY(tq->tq_nthreads == nthreads); 29414c2e0a0SMartin Matuska 29514c2e0a0SMartin Matuska /* spawn all syncthreads */ 29614c2e0a0SMartin Matuska for (int i = 0; i < nthreads; i++) { 29714c2e0a0SMartin Matuska cv_init(&tqs[i].tqa_cv, NULL, CV_DEFAULT, NULL); 29814c2e0a0SMartin Matuska mutex_init(&tqs[i].tqa_lock, NULL, MUTEX_DEFAULT, NULL); 29914c2e0a0SMartin Matuska (void) taskq_dispatch(tq, taskq_sync_assign, 30014c2e0a0SMartin Matuska &tqs[i], TQ_FRONT); 30114c2e0a0SMartin Matuska } 30214c2e0a0SMartin Matuska 30314c2e0a0SMartin Matuska /* wait on all syncthreads to start */ 30414c2e0a0SMartin Matuska for (int i = 0; i < nthreads; i++) { 30514c2e0a0SMartin Matuska mutex_enter(&tqs[i].tqa_lock); 30614c2e0a0SMartin Matuska while (tqs[i].tqa_ready == 0) 30714c2e0a0SMartin Matuska cv_wait(&tqs[i].tqa_cv, &tqs[i].tqa_lock); 30814c2e0a0SMartin Matuska mutex_exit(&tqs[i].tqa_lock); 30914c2e0a0SMartin Matuska } 31014c2e0a0SMartin Matuska 31114c2e0a0SMartin Matuska /* let all syncthreads resume, finish */ 31214c2e0a0SMartin Matuska for (int i = 0; i < nthreads; i++) { 31314c2e0a0SMartin Matuska mutex_enter(&tqs[i].tqa_lock); 31414c2e0a0SMartin Matuska tqs[i].tqa_ready = 2; 31514c2e0a0SMartin Matuska cv_broadcast(&tqs[i].tqa_cv); 31614c2e0a0SMartin Matuska mutex_exit(&tqs[i].tqa_lock); 31714c2e0a0SMartin Matuska } 31814c2e0a0SMartin Matuska taskq_wait(tq); 31914c2e0a0SMartin Matuska 32014c2e0a0SMartin Matuska for (int i = 0; i < nthreads; i++) { 32114c2e0a0SMartin Matuska kthreads[i] = tqs[i].tqa_thread; 32214c2e0a0SMartin Matuska mutex_destroy(&tqs[i].tqa_lock); 32314c2e0a0SMartin Matuska cv_destroy(&tqs[i].tqa_cv); 32414c2e0a0SMartin Matuska } 32514c2e0a0SMartin Matuska kmem_free(tqs, sizeof (*tqs) * nthreads); 32614c2e0a0SMartin Matuska 32714c2e0a0SMartin Matuska *ktpp = kthreads; 32814c2e0a0SMartin Matuska return (tq); 32914c2e0a0SMartin Matuska } 33014c2e0a0SMartin Matuska 331eda14cbcSMatt Macy int 332eda14cbcSMatt Macy taskq_member(taskq_t *tq, kthread_t *thread) 333eda14cbcSMatt Macy { 334eda14cbcSMatt Macy 335eda14cbcSMatt Macy return (taskqueue_member(tq->tq_queue, thread)); 336eda14cbcSMatt Macy } 337eda14cbcSMatt Macy 338eda14cbcSMatt Macy taskq_t * 339eda14cbcSMatt Macy taskq_of_curthread(void) 340eda14cbcSMatt Macy { 341eda14cbcSMatt Macy return (tsd_get(taskq_tsd)); 342eda14cbcSMatt Macy } 343eda14cbcSMatt Macy 344eda14cbcSMatt Macy static void 345eda14cbcSMatt Macy taskq_free(taskq_ent_t *task) 346eda14cbcSMatt Macy { 347eda14cbcSMatt Macy taskq_remove(task); 348eda14cbcSMatt Macy if (refcount_release(&task->tqent_rc)) 349eda14cbcSMatt Macy uma_zfree(taskq_zone, task); 350eda14cbcSMatt Macy } 351eda14cbcSMatt Macy 352eda14cbcSMatt Macy int 353eda14cbcSMatt Macy taskq_cancel_id(taskq_t *tq, taskqid_t tid) 354eda14cbcSMatt Macy { 355eda14cbcSMatt Macy uint32_t pend; 356eda14cbcSMatt Macy int rc; 357eda14cbcSMatt Macy taskq_ent_t *ent; 358eda14cbcSMatt Macy 359eda14cbcSMatt Macy if ((ent = taskq_lookup(tid)) == NULL) 360*7a7741afSMartin Matuska return (ENOENT); 361eda14cbcSMatt Macy 36222b267e8SMartin Matuska if (ent->tqent_type == NORMAL_TASK) { 36322b267e8SMartin Matuska rc = taskqueue_cancel(tq->tq_queue, &ent->tqent_task, &pend); 36422b267e8SMartin Matuska if (rc == EBUSY) 36522b267e8SMartin Matuska taskqueue_drain(tq->tq_queue, &ent->tqent_task); 36622b267e8SMartin Matuska } else { 367eda14cbcSMatt Macy rc = taskqueue_cancel_timeout(tq->tq_queue, 368eda14cbcSMatt Macy &ent->tqent_timeout_task, &pend); 369eda14cbcSMatt Macy if (rc == EBUSY) { 37022b267e8SMartin Matuska taskqueue_drain_timeout(tq->tq_queue, 37122b267e8SMartin Matuska &ent->tqent_timeout_task); 37222b267e8SMartin Matuska } 37322b267e8SMartin Matuska } 37422b267e8SMartin Matuska if (pend) { 375eda14cbcSMatt Macy /* 376eda14cbcSMatt Macy * Tasks normally free themselves when run, but here the task 377eda14cbcSMatt Macy * was cancelled so it did not free itself. 378eda14cbcSMatt Macy */ 379eda14cbcSMatt Macy taskq_free(ent); 380eda14cbcSMatt Macy } 381eda14cbcSMatt Macy /* Free the extra reference we added with taskq_lookup. */ 382eda14cbcSMatt Macy taskq_free(ent); 383*7a7741afSMartin Matuska return (pend ? 0 : ENOENT); 384eda14cbcSMatt Macy } 385eda14cbcSMatt Macy 386eda14cbcSMatt Macy static void 38722b267e8SMartin Matuska taskq_run(void *arg, int pending) 388eda14cbcSMatt Macy { 389eda14cbcSMatt Macy taskq_ent_t *task = arg; 390eda14cbcSMatt Macy 39122b267e8SMartin Matuska if (pending == 0) 39222b267e8SMartin Matuska return; 393eda14cbcSMatt Macy task->tqent_func(task->tqent_arg); 394eda14cbcSMatt Macy taskq_free(task); 395eda14cbcSMatt Macy } 396eda14cbcSMatt Macy 397eda14cbcSMatt Macy taskqid_t 398eda14cbcSMatt Macy taskq_dispatch_delay(taskq_t *tq, task_func_t func, void *arg, 399eda14cbcSMatt Macy uint_t flags, clock_t expire_time) 400eda14cbcSMatt Macy { 401eda14cbcSMatt Macy taskq_ent_t *task; 402c3f8f86eSMateusz Guzik taskqid_t tqid; 403eda14cbcSMatt Macy clock_t timo; 404eda14cbcSMatt Macy int mflag; 405eda14cbcSMatt Macy 406eda14cbcSMatt Macy timo = expire_time - ddi_get_lbolt(); 407eda14cbcSMatt Macy if (timo <= 0) 408eda14cbcSMatt Macy return (taskq_dispatch(tq, func, arg, flags)); 409eda14cbcSMatt Macy 410eda14cbcSMatt Macy if ((flags & (TQ_SLEEP | TQ_NOQUEUE)) == TQ_SLEEP) 411eda14cbcSMatt Macy mflag = M_WAITOK; 412eda14cbcSMatt Macy else 413eda14cbcSMatt Macy mflag = M_NOWAIT; 414eda14cbcSMatt Macy 415eda14cbcSMatt Macy task = uma_zalloc(taskq_zone, mflag); 416eda14cbcSMatt Macy if (task == NULL) 417eda14cbcSMatt Macy return (0); 418eda14cbcSMatt Macy task->tqent_func = func; 419eda14cbcSMatt Macy task->tqent_arg = arg; 420eda14cbcSMatt Macy task->tqent_type = TIMEOUT_TASK; 421eda14cbcSMatt Macy refcount_init(&task->tqent_rc, 1); 422c3f8f86eSMateusz Guzik tqid = taskq_insert(task); 423eda14cbcSMatt Macy TIMEOUT_TASK_INIT(tq->tq_queue, &task->tqent_timeout_task, 0, 424eda14cbcSMatt Macy taskq_run, task); 425eda14cbcSMatt Macy 426eda14cbcSMatt Macy taskqueue_enqueue_timeout(tq->tq_queue, &task->tqent_timeout_task, 427eda14cbcSMatt Macy timo); 428c3f8f86eSMateusz Guzik return (tqid); 429eda14cbcSMatt Macy } 430eda14cbcSMatt Macy 431eda14cbcSMatt Macy taskqid_t 432eda14cbcSMatt Macy taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t flags) 433eda14cbcSMatt Macy { 434eda14cbcSMatt Macy taskq_ent_t *task; 435eda14cbcSMatt Macy int mflag, prio; 436c3f8f86eSMateusz Guzik taskqid_t tqid; 437eda14cbcSMatt Macy 438eda14cbcSMatt Macy if ((flags & (TQ_SLEEP | TQ_NOQUEUE)) == TQ_SLEEP) 439eda14cbcSMatt Macy mflag = M_WAITOK; 440eda14cbcSMatt Macy else 441eda14cbcSMatt Macy mflag = M_NOWAIT; 442eda14cbcSMatt Macy /* 443eda14cbcSMatt Macy * If TQ_FRONT is given, we want higher priority for this task, so it 444eda14cbcSMatt Macy * can go at the front of the queue. 445eda14cbcSMatt Macy */ 446eda14cbcSMatt Macy prio = !!(flags & TQ_FRONT); 447eda14cbcSMatt Macy 448eda14cbcSMatt Macy task = uma_zalloc(taskq_zone, mflag); 449eda14cbcSMatt Macy if (task == NULL) 450eda14cbcSMatt Macy return (0); 451eda14cbcSMatt Macy refcount_init(&task->tqent_rc, 1); 452eda14cbcSMatt Macy task->tqent_func = func; 453eda14cbcSMatt Macy task->tqent_arg = arg; 454eda14cbcSMatt Macy task->tqent_type = NORMAL_TASK; 455c3f8f86eSMateusz Guzik tqid = taskq_insert(task); 456eda14cbcSMatt Macy TASK_INIT(&task->tqent_task, prio, taskq_run, task); 457eda14cbcSMatt Macy taskqueue_enqueue(tq->tq_queue, &task->tqent_task); 458c3f8f86eSMateusz Guzik return (tqid); 459eda14cbcSMatt Macy } 460eda14cbcSMatt Macy 461eda14cbcSMatt Macy static void 46222b267e8SMartin Matuska taskq_run_ent(void *arg, int pending) 463eda14cbcSMatt Macy { 464eda14cbcSMatt Macy taskq_ent_t *task = arg; 465eda14cbcSMatt Macy 46622b267e8SMartin Matuska if (pending == 0) 46722b267e8SMartin Matuska return; 468eda14cbcSMatt Macy task->tqent_func(task->tqent_arg); 469eda14cbcSMatt Macy } 470eda14cbcSMatt Macy 471eda14cbcSMatt Macy void 472eda14cbcSMatt Macy taskq_dispatch_ent(taskq_t *tq, task_func_t func, void *arg, uint32_t flags, 473eda14cbcSMatt Macy taskq_ent_t *task) 474eda14cbcSMatt Macy { 475eda14cbcSMatt Macy /* 476eda14cbcSMatt Macy * If TQ_FRONT is given, we want higher priority for this task, so it 477eda14cbcSMatt Macy * can go at the front of the queue. 478eda14cbcSMatt Macy */ 47914c2e0a0SMartin Matuska task->tqent_task.ta_priority = !!(flags & TQ_FRONT); 480eda14cbcSMatt Macy task->tqent_func = func; 481eda14cbcSMatt Macy task->tqent_arg = arg; 482eda14cbcSMatt Macy taskqueue_enqueue(tq->tq_queue, &task->tqent_task); 483eda14cbcSMatt Macy } 484eda14cbcSMatt Macy 485eda14cbcSMatt Macy void 48614c2e0a0SMartin Matuska taskq_init_ent(taskq_ent_t *task) 48714c2e0a0SMartin Matuska { 48814c2e0a0SMartin Matuska TASK_INIT(&task->tqent_task, 0, taskq_run_ent, task); 48914c2e0a0SMartin Matuska task->tqent_func = NULL; 49014c2e0a0SMartin Matuska task->tqent_arg = NULL; 49114c2e0a0SMartin Matuska task->tqent_id = 0; 49214c2e0a0SMartin Matuska task->tqent_type = NORMAL_TASK; 49314c2e0a0SMartin Matuska task->tqent_rc = 0; 49414c2e0a0SMartin Matuska } 49514c2e0a0SMartin Matuska 49614c2e0a0SMartin Matuska int 49714c2e0a0SMartin Matuska taskq_empty_ent(taskq_ent_t *task) 49814c2e0a0SMartin Matuska { 49914c2e0a0SMartin Matuska return (task->tqent_task.ta_pending == 0); 50014c2e0a0SMartin Matuska } 50114c2e0a0SMartin Matuska 50214c2e0a0SMartin Matuska void 503eda14cbcSMatt Macy taskq_wait(taskq_t *tq) 504eda14cbcSMatt Macy { 505eda14cbcSMatt Macy taskqueue_quiesce(tq->tq_queue); 506eda14cbcSMatt Macy } 507eda14cbcSMatt Macy 508eda14cbcSMatt Macy void 509eda14cbcSMatt Macy taskq_wait_id(taskq_t *tq, taskqid_t tid) 510eda14cbcSMatt Macy { 511eda14cbcSMatt Macy taskq_ent_t *ent; 512eda14cbcSMatt Macy 513eda14cbcSMatt Macy if ((ent = taskq_lookup(tid)) == NULL) 514eda14cbcSMatt Macy return; 515eda14cbcSMatt Macy 51622b267e8SMartin Matuska if (ent->tqent_type == NORMAL_TASK) 517eda14cbcSMatt Macy taskqueue_drain(tq->tq_queue, &ent->tqent_task); 51822b267e8SMartin Matuska else 51922b267e8SMartin Matuska taskqueue_drain_timeout(tq->tq_queue, &ent->tqent_timeout_task); 520eda14cbcSMatt Macy taskq_free(ent); 521eda14cbcSMatt Macy } 522eda14cbcSMatt Macy 523eda14cbcSMatt Macy void 524eda14cbcSMatt Macy taskq_wait_outstanding(taskq_t *tq, taskqid_t id __unused) 525eda14cbcSMatt Macy { 526eda14cbcSMatt Macy taskqueue_drain_all(tq->tq_queue); 527eda14cbcSMatt Macy } 528