1eda14cbcSMatt Macy /* 2eda14cbcSMatt Macy * CDDL HEADER START 3eda14cbcSMatt Macy * 4eda14cbcSMatt Macy * The contents of this file are subject to the terms of the 5eda14cbcSMatt Macy * Common Development and Distribution License (the "License"). 6eda14cbcSMatt Macy * You may not use this file except in compliance with the License. 7eda14cbcSMatt Macy * 8eda14cbcSMatt Macy * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9271171e0SMartin Matuska * or https://opensource.org/licenses/CDDL-1.0. 10eda14cbcSMatt Macy * See the License for the specific language governing permissions 11eda14cbcSMatt Macy * and limitations under the License. 12eda14cbcSMatt Macy * 13eda14cbcSMatt Macy * When distributing Covered Code, include this CDDL HEADER in each 14eda14cbcSMatt Macy * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15eda14cbcSMatt Macy * If applicable, add the following below this CDDL HEADER, with the 16eda14cbcSMatt Macy * fields enclosed by brackets "[]" replaced with your own identifying 17eda14cbcSMatt Macy * information: Portions Copyright [yyyy] [name of copyright owner] 18eda14cbcSMatt Macy * 19eda14cbcSMatt Macy * CDDL HEADER END 20eda14cbcSMatt Macy */ 21eda14cbcSMatt Macy /* 22eda14cbcSMatt Macy * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23eda14cbcSMatt Macy * Use is subject to license terms. 24eda14cbcSMatt Macy */ 25eda14cbcSMatt Macy /* 26eda14cbcSMatt Macy * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 27eda14cbcSMatt Macy * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved. 28eda14cbcSMatt Macy * Copyright (c) 2014 by Delphix. All rights reserved. 29eda14cbcSMatt Macy */ 30eda14cbcSMatt Macy 31eda14cbcSMatt Macy #include <sys/zfs_context.h> 32eda14cbcSMatt Macy 33eda14cbcSMatt Macy int taskq_now; 34eda14cbcSMatt Macy taskq_t *system_taskq; 35eda14cbcSMatt Macy taskq_t *system_delay_taskq; 36eda14cbcSMatt Macy 37eda14cbcSMatt Macy static pthread_key_t taskq_tsd; 38eda14cbcSMatt Macy 39eda14cbcSMatt Macy #define TASKQ_ACTIVE 0x00010000 40eda14cbcSMatt Macy 41eda14cbcSMatt Macy static taskq_ent_t * 42eda14cbcSMatt Macy task_alloc(taskq_t *tq, int tqflags) 43eda14cbcSMatt Macy { 44eda14cbcSMatt Macy taskq_ent_t *t; 45eda14cbcSMatt Macy int rv; 46eda14cbcSMatt Macy 47eda14cbcSMatt Macy again: if ((t = tq->tq_freelist) != NULL && tq->tq_nalloc >= tq->tq_minalloc) { 48eda14cbcSMatt Macy ASSERT(!(t->tqent_flags & TQENT_FLAG_PREALLOC)); 49eda14cbcSMatt Macy tq->tq_freelist = t->tqent_next; 50eda14cbcSMatt Macy } else { 51eda14cbcSMatt Macy if (tq->tq_nalloc >= tq->tq_maxalloc) { 52eda14cbcSMatt Macy if (!(tqflags & KM_SLEEP)) 53eda14cbcSMatt Macy return (NULL); 54eda14cbcSMatt Macy 55eda14cbcSMatt Macy /* 56eda14cbcSMatt Macy * We don't want to exceed tq_maxalloc, but we can't 57eda14cbcSMatt Macy * wait for other tasks to complete (and thus free up 58eda14cbcSMatt Macy * task structures) without risking deadlock with 59eda14cbcSMatt Macy * the caller. So, we just delay for one second 60eda14cbcSMatt Macy * to throttle the allocation rate. If we have tasks 61eda14cbcSMatt Macy * complete before one second timeout expires then 62eda14cbcSMatt Macy * taskq_ent_free will signal us and we will 63eda14cbcSMatt Macy * immediately retry the allocation. 64eda14cbcSMatt Macy */ 65eda14cbcSMatt Macy tq->tq_maxalloc_wait++; 66eda14cbcSMatt Macy rv = cv_timedwait(&tq->tq_maxalloc_cv, 67eda14cbcSMatt Macy &tq->tq_lock, ddi_get_lbolt() + hz); 68eda14cbcSMatt Macy tq->tq_maxalloc_wait--; 69eda14cbcSMatt Macy if (rv > 0) 70eda14cbcSMatt Macy goto again; /* signaled */ 71eda14cbcSMatt Macy } 72eda14cbcSMatt Macy mutex_exit(&tq->tq_lock); 73eda14cbcSMatt Macy 74eda14cbcSMatt Macy t = kmem_alloc(sizeof (taskq_ent_t), tqflags); 75eda14cbcSMatt Macy 76eda14cbcSMatt Macy mutex_enter(&tq->tq_lock); 77eda14cbcSMatt Macy if (t != NULL) { 78eda14cbcSMatt Macy /* Make sure we start without any flags */ 79eda14cbcSMatt Macy t->tqent_flags = 0; 80eda14cbcSMatt Macy tq->tq_nalloc++; 81eda14cbcSMatt Macy } 82eda14cbcSMatt Macy } 83eda14cbcSMatt Macy return (t); 84eda14cbcSMatt Macy } 85eda14cbcSMatt Macy 86eda14cbcSMatt Macy static void 87eda14cbcSMatt Macy task_free(taskq_t *tq, taskq_ent_t *t) 88eda14cbcSMatt Macy { 89eda14cbcSMatt Macy if (tq->tq_nalloc <= tq->tq_minalloc) { 90eda14cbcSMatt Macy t->tqent_next = tq->tq_freelist; 91eda14cbcSMatt Macy tq->tq_freelist = t; 92eda14cbcSMatt Macy } else { 93eda14cbcSMatt Macy tq->tq_nalloc--; 94eda14cbcSMatt Macy mutex_exit(&tq->tq_lock); 95eda14cbcSMatt Macy kmem_free(t, sizeof (taskq_ent_t)); 96eda14cbcSMatt Macy mutex_enter(&tq->tq_lock); 97eda14cbcSMatt Macy } 98eda14cbcSMatt Macy 99eda14cbcSMatt Macy if (tq->tq_maxalloc_wait) 100eda14cbcSMatt Macy cv_signal(&tq->tq_maxalloc_cv); 101eda14cbcSMatt Macy } 102eda14cbcSMatt Macy 103eda14cbcSMatt Macy taskqid_t 104eda14cbcSMatt Macy taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t tqflags) 105eda14cbcSMatt Macy { 106eda14cbcSMatt Macy taskq_ent_t *t; 107eda14cbcSMatt Macy 108eda14cbcSMatt Macy if (taskq_now) { 109eda14cbcSMatt Macy func(arg); 110eda14cbcSMatt Macy return (1); 111eda14cbcSMatt Macy } 112eda14cbcSMatt Macy 113eda14cbcSMatt Macy mutex_enter(&tq->tq_lock); 114eda14cbcSMatt Macy ASSERT(tq->tq_flags & TASKQ_ACTIVE); 115eda14cbcSMatt Macy if ((t = task_alloc(tq, tqflags)) == NULL) { 116eda14cbcSMatt Macy mutex_exit(&tq->tq_lock); 117eda14cbcSMatt Macy return (0); 118eda14cbcSMatt Macy } 119eda14cbcSMatt Macy if (tqflags & TQ_FRONT) { 120eda14cbcSMatt Macy t->tqent_next = tq->tq_task.tqent_next; 121eda14cbcSMatt Macy t->tqent_prev = &tq->tq_task; 122eda14cbcSMatt Macy } else { 123eda14cbcSMatt Macy t->tqent_next = &tq->tq_task; 124eda14cbcSMatt Macy t->tqent_prev = tq->tq_task.tqent_prev; 125eda14cbcSMatt Macy } 126eda14cbcSMatt Macy t->tqent_next->tqent_prev = t; 127eda14cbcSMatt Macy t->tqent_prev->tqent_next = t; 128eda14cbcSMatt Macy t->tqent_func = func; 129eda14cbcSMatt Macy t->tqent_arg = arg; 130eda14cbcSMatt Macy t->tqent_flags = 0; 131eda14cbcSMatt Macy cv_signal(&tq->tq_dispatch_cv); 132eda14cbcSMatt Macy mutex_exit(&tq->tq_lock); 133eda14cbcSMatt Macy return (1); 134eda14cbcSMatt Macy } 135eda14cbcSMatt Macy 136eda14cbcSMatt Macy taskqid_t 137eda14cbcSMatt Macy taskq_dispatch_delay(taskq_t *tq, task_func_t func, void *arg, uint_t tqflags, 138eda14cbcSMatt Macy clock_t expire_time) 139eda14cbcSMatt Macy { 140e92ffd9bSMartin Matuska (void) tq, (void) func, (void) arg, (void) tqflags, (void) expire_time; 141eda14cbcSMatt Macy return (0); 142eda14cbcSMatt Macy } 143eda14cbcSMatt Macy 144eda14cbcSMatt Macy int 145eda14cbcSMatt Macy taskq_empty_ent(taskq_ent_t *t) 146eda14cbcSMatt Macy { 147eda14cbcSMatt Macy return (t->tqent_next == NULL); 148eda14cbcSMatt Macy } 149eda14cbcSMatt Macy 150eda14cbcSMatt Macy void 151eda14cbcSMatt Macy taskq_init_ent(taskq_ent_t *t) 152eda14cbcSMatt Macy { 153eda14cbcSMatt Macy t->tqent_next = NULL; 154eda14cbcSMatt Macy t->tqent_prev = NULL; 155eda14cbcSMatt Macy t->tqent_func = NULL; 156eda14cbcSMatt Macy t->tqent_arg = NULL; 157eda14cbcSMatt Macy t->tqent_flags = 0; 158eda14cbcSMatt Macy } 159eda14cbcSMatt Macy 160eda14cbcSMatt Macy void 161eda14cbcSMatt Macy taskq_dispatch_ent(taskq_t *tq, task_func_t func, void *arg, uint_t flags, 162eda14cbcSMatt Macy taskq_ent_t *t) 163eda14cbcSMatt Macy { 164eda14cbcSMatt Macy ASSERT(func != NULL); 165eda14cbcSMatt Macy 166eda14cbcSMatt Macy /* 167eda14cbcSMatt Macy * Mark it as a prealloc'd task. This is important 168eda14cbcSMatt Macy * to ensure that we don't free it later. 169eda14cbcSMatt Macy */ 170eda14cbcSMatt Macy t->tqent_flags |= TQENT_FLAG_PREALLOC; 171eda14cbcSMatt Macy /* 172eda14cbcSMatt Macy * Enqueue the task to the underlying queue. 173eda14cbcSMatt Macy */ 174eda14cbcSMatt Macy mutex_enter(&tq->tq_lock); 175eda14cbcSMatt Macy 176eda14cbcSMatt Macy if (flags & TQ_FRONT) { 177eda14cbcSMatt Macy t->tqent_next = tq->tq_task.tqent_next; 178eda14cbcSMatt Macy t->tqent_prev = &tq->tq_task; 179eda14cbcSMatt Macy } else { 180eda14cbcSMatt Macy t->tqent_next = &tq->tq_task; 181eda14cbcSMatt Macy t->tqent_prev = tq->tq_task.tqent_prev; 182eda14cbcSMatt Macy } 183eda14cbcSMatt Macy t->tqent_next->tqent_prev = t; 184eda14cbcSMatt Macy t->tqent_prev->tqent_next = t; 185eda14cbcSMatt Macy t->tqent_func = func; 186eda14cbcSMatt Macy t->tqent_arg = arg; 187eda14cbcSMatt Macy cv_signal(&tq->tq_dispatch_cv); 188eda14cbcSMatt Macy mutex_exit(&tq->tq_lock); 189eda14cbcSMatt Macy } 190eda14cbcSMatt Macy 191eda14cbcSMatt Macy void 192eda14cbcSMatt Macy taskq_wait(taskq_t *tq) 193eda14cbcSMatt Macy { 194eda14cbcSMatt Macy mutex_enter(&tq->tq_lock); 195eda14cbcSMatt Macy while (tq->tq_task.tqent_next != &tq->tq_task || tq->tq_active != 0) 196eda14cbcSMatt Macy cv_wait(&tq->tq_wait_cv, &tq->tq_lock); 197eda14cbcSMatt Macy mutex_exit(&tq->tq_lock); 198eda14cbcSMatt Macy } 199eda14cbcSMatt Macy 200eda14cbcSMatt Macy void 201eda14cbcSMatt Macy taskq_wait_id(taskq_t *tq, taskqid_t id) 202eda14cbcSMatt Macy { 203e92ffd9bSMartin Matuska (void) id; 204eda14cbcSMatt Macy taskq_wait(tq); 205eda14cbcSMatt Macy } 206eda14cbcSMatt Macy 207eda14cbcSMatt Macy void 208eda14cbcSMatt Macy taskq_wait_outstanding(taskq_t *tq, taskqid_t id) 209eda14cbcSMatt Macy { 210e92ffd9bSMartin Matuska (void) id; 211eda14cbcSMatt Macy taskq_wait(tq); 212eda14cbcSMatt Macy } 213eda14cbcSMatt Macy 214da5137abSMartin Matuska static __attribute__((noreturn)) void 215eda14cbcSMatt Macy taskq_thread(void *arg) 216eda14cbcSMatt Macy { 217eda14cbcSMatt Macy taskq_t *tq = arg; 218eda14cbcSMatt Macy taskq_ent_t *t; 219eda14cbcSMatt Macy boolean_t prealloc; 220eda14cbcSMatt Macy 221eda14cbcSMatt Macy VERIFY0(pthread_setspecific(taskq_tsd, tq)); 222eda14cbcSMatt Macy 223eda14cbcSMatt Macy mutex_enter(&tq->tq_lock); 224eda14cbcSMatt Macy while (tq->tq_flags & TASKQ_ACTIVE) { 225eda14cbcSMatt Macy if ((t = tq->tq_task.tqent_next) == &tq->tq_task) { 226eda14cbcSMatt Macy if (--tq->tq_active == 0) 227eda14cbcSMatt Macy cv_broadcast(&tq->tq_wait_cv); 228eda14cbcSMatt Macy cv_wait(&tq->tq_dispatch_cv, &tq->tq_lock); 229eda14cbcSMatt Macy tq->tq_active++; 230eda14cbcSMatt Macy continue; 231eda14cbcSMatt Macy } 232eda14cbcSMatt Macy t->tqent_prev->tqent_next = t->tqent_next; 233eda14cbcSMatt Macy t->tqent_next->tqent_prev = t->tqent_prev; 234eda14cbcSMatt Macy t->tqent_next = NULL; 235eda14cbcSMatt Macy t->tqent_prev = NULL; 236eda14cbcSMatt Macy prealloc = t->tqent_flags & TQENT_FLAG_PREALLOC; 237eda14cbcSMatt Macy mutex_exit(&tq->tq_lock); 238eda14cbcSMatt Macy 239eda14cbcSMatt Macy rw_enter(&tq->tq_threadlock, RW_READER); 240eda14cbcSMatt Macy t->tqent_func(t->tqent_arg); 241eda14cbcSMatt Macy rw_exit(&tq->tq_threadlock); 242eda14cbcSMatt Macy 243eda14cbcSMatt Macy mutex_enter(&tq->tq_lock); 244eda14cbcSMatt Macy if (!prealloc) 245eda14cbcSMatt Macy task_free(tq, t); 246eda14cbcSMatt Macy } 247eda14cbcSMatt Macy tq->tq_nthreads--; 248eda14cbcSMatt Macy cv_broadcast(&tq->tq_wait_cv); 249eda14cbcSMatt Macy mutex_exit(&tq->tq_lock); 250eda14cbcSMatt Macy thread_exit(); 251eda14cbcSMatt Macy } 252eda14cbcSMatt Macy 253eda14cbcSMatt Macy taskq_t * 254eda14cbcSMatt Macy taskq_create(const char *name, int nthreads, pri_t pri, 255eda14cbcSMatt Macy int minalloc, int maxalloc, uint_t flags) 256eda14cbcSMatt Macy { 257e92ffd9bSMartin Matuska (void) pri; 258eda14cbcSMatt Macy taskq_t *tq = kmem_zalloc(sizeof (taskq_t), KM_SLEEP); 259eda14cbcSMatt Macy int t; 260eda14cbcSMatt Macy 261eda14cbcSMatt Macy if (flags & TASKQ_THREADS_CPU_PCT) { 262eda14cbcSMatt Macy int pct; 263eda14cbcSMatt Macy ASSERT3S(nthreads, >=, 0); 264eda14cbcSMatt Macy ASSERT3S(nthreads, <=, 100); 265eda14cbcSMatt Macy pct = MIN(nthreads, 100); 266eda14cbcSMatt Macy pct = MAX(pct, 0); 267eda14cbcSMatt Macy 268eda14cbcSMatt Macy nthreads = (sysconf(_SC_NPROCESSORS_ONLN) * pct) / 100; 269eda14cbcSMatt Macy nthreads = MAX(nthreads, 1); /* need at least 1 thread */ 270eda14cbcSMatt Macy } else { 271eda14cbcSMatt Macy ASSERT3S(nthreads, >=, 1); 272eda14cbcSMatt Macy } 273eda14cbcSMatt Macy 274eda14cbcSMatt Macy rw_init(&tq->tq_threadlock, NULL, RW_DEFAULT, NULL); 275eda14cbcSMatt Macy mutex_init(&tq->tq_lock, NULL, MUTEX_DEFAULT, NULL); 276eda14cbcSMatt Macy cv_init(&tq->tq_dispatch_cv, NULL, CV_DEFAULT, NULL); 277eda14cbcSMatt Macy cv_init(&tq->tq_wait_cv, NULL, CV_DEFAULT, NULL); 278eda14cbcSMatt Macy cv_init(&tq->tq_maxalloc_cv, NULL, CV_DEFAULT, NULL); 279be181ee2SMartin Matuska (void) strlcpy(tq->tq_name, name, sizeof (tq->tq_name)); 280eda14cbcSMatt Macy tq->tq_flags = flags | TASKQ_ACTIVE; 281eda14cbcSMatt Macy tq->tq_active = nthreads; 282eda14cbcSMatt Macy tq->tq_nthreads = nthreads; 283eda14cbcSMatt Macy tq->tq_minalloc = minalloc; 284eda14cbcSMatt Macy tq->tq_maxalloc = maxalloc; 285eda14cbcSMatt Macy tq->tq_task.tqent_next = &tq->tq_task; 286eda14cbcSMatt Macy tq->tq_task.tqent_prev = &tq->tq_task; 287eda14cbcSMatt Macy tq->tq_threadlist = kmem_alloc(nthreads * sizeof (kthread_t *), 288eda14cbcSMatt Macy KM_SLEEP); 289eda14cbcSMatt Macy 290eda14cbcSMatt Macy if (flags & TASKQ_PREPOPULATE) { 291eda14cbcSMatt Macy mutex_enter(&tq->tq_lock); 292eda14cbcSMatt Macy while (minalloc-- > 0) 293eda14cbcSMatt Macy task_free(tq, task_alloc(tq, KM_SLEEP)); 294eda14cbcSMatt Macy mutex_exit(&tq->tq_lock); 295eda14cbcSMatt Macy } 296eda14cbcSMatt Macy 297eda14cbcSMatt Macy for (t = 0; t < nthreads; t++) 298eda14cbcSMatt Macy VERIFY((tq->tq_threadlist[t] = thread_create(NULL, 0, 299eda14cbcSMatt Macy taskq_thread, tq, 0, &p0, TS_RUN, pri)) != NULL); 300eda14cbcSMatt Macy 301eda14cbcSMatt Macy return (tq); 302eda14cbcSMatt Macy } 303eda14cbcSMatt Macy 304eda14cbcSMatt Macy void 305eda14cbcSMatt Macy taskq_destroy(taskq_t *tq) 306eda14cbcSMatt Macy { 307eda14cbcSMatt Macy int nthreads = tq->tq_nthreads; 308eda14cbcSMatt Macy 309eda14cbcSMatt Macy taskq_wait(tq); 310eda14cbcSMatt Macy 311eda14cbcSMatt Macy mutex_enter(&tq->tq_lock); 312eda14cbcSMatt Macy 313eda14cbcSMatt Macy tq->tq_flags &= ~TASKQ_ACTIVE; 314eda14cbcSMatt Macy cv_broadcast(&tq->tq_dispatch_cv); 315eda14cbcSMatt Macy 316eda14cbcSMatt Macy while (tq->tq_nthreads != 0) 317eda14cbcSMatt Macy cv_wait(&tq->tq_wait_cv, &tq->tq_lock); 318eda14cbcSMatt Macy 319eda14cbcSMatt Macy tq->tq_minalloc = 0; 320eda14cbcSMatt Macy while (tq->tq_nalloc != 0) { 321eda14cbcSMatt Macy ASSERT(tq->tq_freelist != NULL); 322be181ee2SMartin Matuska taskq_ent_t *tqent_nexttq = tq->tq_freelist->tqent_next; 323be181ee2SMartin Matuska task_free(tq, tq->tq_freelist); 324be181ee2SMartin Matuska tq->tq_freelist = tqent_nexttq; 325eda14cbcSMatt Macy } 326eda14cbcSMatt Macy 327eda14cbcSMatt Macy mutex_exit(&tq->tq_lock); 328eda14cbcSMatt Macy 329eda14cbcSMatt Macy kmem_free(tq->tq_threadlist, nthreads * sizeof (kthread_t *)); 330eda14cbcSMatt Macy 331eda14cbcSMatt Macy rw_destroy(&tq->tq_threadlock); 332eda14cbcSMatt Macy mutex_destroy(&tq->tq_lock); 333eda14cbcSMatt Macy cv_destroy(&tq->tq_dispatch_cv); 334eda14cbcSMatt Macy cv_destroy(&tq->tq_wait_cv); 335eda14cbcSMatt Macy cv_destroy(&tq->tq_maxalloc_cv); 336eda14cbcSMatt Macy 337eda14cbcSMatt Macy kmem_free(tq, sizeof (taskq_t)); 338eda14cbcSMatt Macy } 339eda14cbcSMatt Macy 340*14c2e0a0SMartin Matuska /* 341*14c2e0a0SMartin Matuska * Create a taskq with a specified number of pool threads. Allocate 342*14c2e0a0SMartin Matuska * and return an array of nthreads kthread_t pointers, one for each 343*14c2e0a0SMartin Matuska * thread in the pool. The array is not ordered and must be freed 344*14c2e0a0SMartin Matuska * by the caller. 345*14c2e0a0SMartin Matuska */ 346*14c2e0a0SMartin Matuska taskq_t * 347*14c2e0a0SMartin Matuska taskq_create_synced(const char *name, int nthreads, pri_t pri, 348*14c2e0a0SMartin Matuska int minalloc, int maxalloc, uint_t flags, kthread_t ***ktpp) 349*14c2e0a0SMartin Matuska { 350*14c2e0a0SMartin Matuska taskq_t *tq; 351*14c2e0a0SMartin Matuska kthread_t **kthreads = kmem_zalloc(sizeof (*kthreads) * nthreads, 352*14c2e0a0SMartin Matuska KM_SLEEP); 353*14c2e0a0SMartin Matuska 354*14c2e0a0SMartin Matuska (void) pri; (void) minalloc; (void) maxalloc; 355*14c2e0a0SMartin Matuska 356*14c2e0a0SMartin Matuska flags &= ~(TASKQ_DYNAMIC | TASKQ_THREADS_CPU_PCT | TASKQ_DC_BATCH); 357*14c2e0a0SMartin Matuska 358*14c2e0a0SMartin Matuska tq = taskq_create(name, nthreads, minclsyspri, nthreads, INT_MAX, 359*14c2e0a0SMartin Matuska flags | TASKQ_PREPOPULATE); 360*14c2e0a0SMartin Matuska VERIFY(tq != NULL); 361*14c2e0a0SMartin Matuska VERIFY(tq->tq_nthreads == nthreads); 362*14c2e0a0SMartin Matuska 363*14c2e0a0SMartin Matuska for (int i = 0; i < nthreads; i++) { 364*14c2e0a0SMartin Matuska kthreads[i] = tq->tq_threadlist[i]; 365*14c2e0a0SMartin Matuska } 366*14c2e0a0SMartin Matuska *ktpp = kthreads; 367*14c2e0a0SMartin Matuska return (tq); 368*14c2e0a0SMartin Matuska } 369*14c2e0a0SMartin Matuska 370eda14cbcSMatt Macy int 371eda14cbcSMatt Macy taskq_member(taskq_t *tq, kthread_t *t) 372eda14cbcSMatt Macy { 373eda14cbcSMatt Macy int i; 374eda14cbcSMatt Macy 375eda14cbcSMatt Macy if (taskq_now) 376eda14cbcSMatt Macy return (1); 377eda14cbcSMatt Macy 378eda14cbcSMatt Macy for (i = 0; i < tq->tq_nthreads; i++) 379eda14cbcSMatt Macy if (tq->tq_threadlist[i] == t) 380eda14cbcSMatt Macy return (1); 381eda14cbcSMatt Macy 382eda14cbcSMatt Macy return (0); 383eda14cbcSMatt Macy } 384eda14cbcSMatt Macy 385eda14cbcSMatt Macy taskq_t * 386eda14cbcSMatt Macy taskq_of_curthread(void) 387eda14cbcSMatt Macy { 388eda14cbcSMatt Macy return (pthread_getspecific(taskq_tsd)); 389eda14cbcSMatt Macy } 390eda14cbcSMatt Macy 391eda14cbcSMatt Macy int 392eda14cbcSMatt Macy taskq_cancel_id(taskq_t *tq, taskqid_t id) 393eda14cbcSMatt Macy { 394e92ffd9bSMartin Matuska (void) tq, (void) id; 395eda14cbcSMatt Macy return (ENOENT); 396eda14cbcSMatt Macy } 397eda14cbcSMatt Macy 398eda14cbcSMatt Macy void 399eda14cbcSMatt Macy system_taskq_init(void) 400eda14cbcSMatt Macy { 401eda14cbcSMatt Macy VERIFY0(pthread_key_create(&taskq_tsd, NULL)); 402eda14cbcSMatt Macy system_taskq = taskq_create("system_taskq", 64, maxclsyspri, 4, 512, 403eda14cbcSMatt Macy TASKQ_DYNAMIC | TASKQ_PREPOPULATE); 404eda14cbcSMatt Macy system_delay_taskq = taskq_create("delay_taskq", 4, maxclsyspri, 4, 405eda14cbcSMatt Macy 512, TASKQ_DYNAMIC | TASKQ_PREPOPULATE); 406eda14cbcSMatt Macy } 407eda14cbcSMatt Macy 408eda14cbcSMatt Macy void 409eda14cbcSMatt Macy system_taskq_fini(void) 410eda14cbcSMatt Macy { 411eda14cbcSMatt Macy taskq_destroy(system_taskq); 412eda14cbcSMatt Macy system_taskq = NULL; /* defensive */ 413eda14cbcSMatt Macy taskq_destroy(system_delay_taskq); 414eda14cbcSMatt Macy system_delay_taskq = NULL; 415eda14cbcSMatt Macy VERIFY0(pthread_key_delete(taskq_tsd)); 416eda14cbcSMatt Macy } 417