1b819cea2SGordon Ross /*
2b819cea2SGordon Ross * CDDL HEADER START
3b819cea2SGordon Ross *
4b819cea2SGordon Ross * The contents of this file are subject to the terms of the
5b819cea2SGordon Ross * Common Development and Distribution License (the "License").
6b819cea2SGordon Ross * You may not use this file except in compliance with the License.
7b819cea2SGordon Ross *
8b819cea2SGordon Ross * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9b819cea2SGordon Ross * or http://www.opensolaris.org/os/licensing.
10b819cea2SGordon Ross * See the License for the specific language governing permissions
11b819cea2SGordon Ross * and limitations under the License.
12b819cea2SGordon Ross *
13b819cea2SGordon Ross * When distributing Covered Code, include this CDDL HEADER in each
14b819cea2SGordon Ross * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15b819cea2SGordon Ross * If applicable, add the following below this CDDL HEADER, with the
16b819cea2SGordon Ross * fields enclosed by brackets "[]" replaced with your own identifying
17b819cea2SGordon Ross * information: Portions Copyright [yyyy] [name of copyright owner]
18b819cea2SGordon Ross *
19b819cea2SGordon Ross * CDDL HEADER END
20b819cea2SGordon Ross */
21b819cea2SGordon Ross /*
22b819cea2SGordon Ross * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23b819cea2SGordon Ross * Use is subject to license terms.
24b819cea2SGordon Ross */
25b819cea2SGordon Ross /*
26b819cea2SGordon Ross * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
27b819cea2SGordon Ross * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
28f06dce2cSAndrew Stormont * Copyright 2017 RackTop Systems.
294c99ecc3STim Kordas * Copyright 2018, Joyent, Inc.
30b819cea2SGordon Ross */
31b819cea2SGordon Ross
32b819cea2SGordon Ross #include <sys/taskq_impl.h>
33b819cea2SGordon Ross
34b819cea2SGordon Ross #include <sys/class.h>
35b819cea2SGordon Ross #include <sys/debug.h>
36b819cea2SGordon Ross #include <sys/ksynch.h>
37b819cea2SGordon Ross #include <sys/kmem.h>
38b819cea2SGordon Ross #include <sys/time.h>
39b819cea2SGordon Ross #include <sys/systm.h>
40b819cea2SGordon Ross #include <sys/sysmacros.h>
41b819cea2SGordon Ross #include <sys/unistd.h>
42b819cea2SGordon Ross
43f06dce2cSAndrew Stormont /* avoid <sys/disp.h> */
44f06dce2cSAndrew Stormont #define maxclsyspri 99
45f06dce2cSAndrew Stormont
46b819cea2SGordon Ross /* avoid <unistd.h> */
47b819cea2SGordon Ross extern long sysconf(int);
48b819cea2SGordon Ross
49b819cea2SGordon Ross /* avoiding <thread.h> */
50b819cea2SGordon Ross typedef unsigned int thread_t;
51b819cea2SGordon Ross typedef unsigned int thread_key_t;
52b819cea2SGordon Ross
53b819cea2SGordon Ross extern int thr_create(void *, size_t, void *(*)(void *), void *, long,
54b819cea2SGordon Ross thread_t *);
55b819cea2SGordon Ross extern int thr_join(thread_t, thread_t *, void **);
56b819cea2SGordon Ross
57b819cea2SGordon Ross /*
58b819cea2SGordon Ross * POSIX.1c Note:
59b819cea2SGordon Ross * THR_BOUND is defined same as PTHREAD_SCOPE_SYSTEM in <pthread.h>
60b819cea2SGordon Ross * THR_DETACHED is defined same as PTHREAD_CREATE_DETACHED in <pthread.h>
61b819cea2SGordon Ross * Any changes in these definitions should be reflected in <pthread.h>
62b819cea2SGordon Ross */
63b819cea2SGordon Ross #define THR_BOUND 0x00000001 /* = PTHREAD_SCOPE_SYSTEM */
64b819cea2SGordon Ross #define THR_NEW_LWP 0x00000002
65b819cea2SGordon Ross #define THR_DETACHED 0x00000040 /* = PTHREAD_CREATE_DETACHED */
66b819cea2SGordon Ross #define THR_SUSPENDED 0x00000080
67b819cea2SGordon Ross #define THR_DAEMON 0x00000100
68b819cea2SGordon Ross
69b819cea2SGordon Ross
70b819cea2SGordon Ross int taskq_now;
71b819cea2SGordon Ross taskq_t *system_taskq;
72b819cea2SGordon Ross
73b819cea2SGordon Ross #define TASKQ_ACTIVE 0x00010000
74b819cea2SGordon Ross
75b819cea2SGordon Ross struct taskq {
76b819cea2SGordon Ross kmutex_t tq_lock;
77b819cea2SGordon Ross krwlock_t tq_threadlock;
78b819cea2SGordon Ross kcondvar_t tq_dispatch_cv;
79b819cea2SGordon Ross kcondvar_t tq_wait_cv;
80b819cea2SGordon Ross thread_t *tq_threadlist;
81b819cea2SGordon Ross int tq_flags;
82b819cea2SGordon Ross int tq_active;
83b819cea2SGordon Ross int tq_nthreads;
84b819cea2SGordon Ross int tq_nalloc;
85b819cea2SGordon Ross int tq_minalloc;
86b819cea2SGordon Ross int tq_maxalloc;
87b819cea2SGordon Ross kcondvar_t tq_maxalloc_cv;
88b819cea2SGordon Ross int tq_maxalloc_wait;
89b819cea2SGordon Ross taskq_ent_t *tq_freelist;
90b819cea2SGordon Ross taskq_ent_t tq_task;
91b819cea2SGordon Ross };
92b819cea2SGordon Ross
93b819cea2SGordon Ross static taskq_ent_t *
task_alloc(taskq_t * tq,int tqflags)94b819cea2SGordon Ross task_alloc(taskq_t *tq, int tqflags)
95b819cea2SGordon Ross {
96b819cea2SGordon Ross taskq_ent_t *t;
97b819cea2SGordon Ross int rv;
98b819cea2SGordon Ross
99b819cea2SGordon Ross again: if ((t = tq->tq_freelist) != NULL && tq->tq_nalloc >= tq->tq_minalloc) {
100b819cea2SGordon Ross tq->tq_freelist = t->tqent_next;
101b819cea2SGordon Ross } else {
102b819cea2SGordon Ross if (tq->tq_nalloc >= tq->tq_maxalloc) {
103eda5fc90SJohn Levon if (tqflags & KM_NOSLEEP)
104b819cea2SGordon Ross return (NULL);
105b819cea2SGordon Ross
106b819cea2SGordon Ross /*
107b819cea2SGordon Ross * We don't want to exceed tq_maxalloc, but we can't
108b819cea2SGordon Ross * wait for other tasks to complete (and thus free up
109b819cea2SGordon Ross * task structures) without risking deadlock with
110b819cea2SGordon Ross * the caller. So, we just delay for one second
111b819cea2SGordon Ross * to throttle the allocation rate. If we have tasks
112b819cea2SGordon Ross * complete before one second timeout expires then
113b819cea2SGordon Ross * taskq_ent_free will signal us and we will
114b819cea2SGordon Ross * immediately retry the allocation.
115b819cea2SGordon Ross */
116b819cea2SGordon Ross tq->tq_maxalloc_wait++;
117b819cea2SGordon Ross rv = cv_timedwait(&tq->tq_maxalloc_cv,
118b819cea2SGordon Ross &tq->tq_lock, ddi_get_lbolt() + hz);
119b819cea2SGordon Ross tq->tq_maxalloc_wait--;
120b819cea2SGordon Ross if (rv > 0)
121b819cea2SGordon Ross goto again; /* signaled */
122b819cea2SGordon Ross }
123b819cea2SGordon Ross mutex_exit(&tq->tq_lock);
124b819cea2SGordon Ross
125b819cea2SGordon Ross t = kmem_alloc(sizeof (taskq_ent_t), tqflags);
126b819cea2SGordon Ross
127b819cea2SGordon Ross mutex_enter(&tq->tq_lock);
128b819cea2SGordon Ross if (t != NULL)
129b819cea2SGordon Ross tq->tq_nalloc++;
130b819cea2SGordon Ross }
131b819cea2SGordon Ross return (t);
132b819cea2SGordon Ross }
133b819cea2SGordon Ross
134b819cea2SGordon Ross static void
task_free(taskq_t * tq,taskq_ent_t * t)135b819cea2SGordon Ross task_free(taskq_t *tq, taskq_ent_t *t)
136b819cea2SGordon Ross {
137b819cea2SGordon Ross if (tq->tq_nalloc <= tq->tq_minalloc) {
138b819cea2SGordon Ross t->tqent_next = tq->tq_freelist;
139b819cea2SGordon Ross tq->tq_freelist = t;
140b819cea2SGordon Ross } else {
141b819cea2SGordon Ross tq->tq_nalloc--;
142b819cea2SGordon Ross mutex_exit(&tq->tq_lock);
143b819cea2SGordon Ross kmem_free(t, sizeof (taskq_ent_t));
144b819cea2SGordon Ross mutex_enter(&tq->tq_lock);
145b819cea2SGordon Ross }
146b819cea2SGordon Ross
147b819cea2SGordon Ross if (tq->tq_maxalloc_wait)
148b819cea2SGordon Ross cv_signal(&tq->tq_maxalloc_cv);
149b819cea2SGordon Ross }
150b819cea2SGordon Ross
151b819cea2SGordon Ross taskqid_t
taskq_dispatch(taskq_t * tq,task_func_t func,void * arg,uint_t tqflags)152b819cea2SGordon Ross taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t tqflags)
153b819cea2SGordon Ross {
154b819cea2SGordon Ross taskq_ent_t *t;
155b819cea2SGordon Ross
156b819cea2SGordon Ross if (taskq_now) {
157b819cea2SGordon Ross func(arg);
158b819cea2SGordon Ross return (1);
159b819cea2SGordon Ross }
160b819cea2SGordon Ross
161b819cea2SGordon Ross mutex_enter(&tq->tq_lock);
162b819cea2SGordon Ross ASSERT(tq->tq_flags & TASKQ_ACTIVE);
163b819cea2SGordon Ross if ((t = task_alloc(tq, tqflags)) == NULL) {
164b819cea2SGordon Ross mutex_exit(&tq->tq_lock);
165fc8ae2ecSToomas Soome return (TASKQID_INVALID);
166b819cea2SGordon Ross }
167b819cea2SGordon Ross if (tqflags & TQ_FRONT) {
168b819cea2SGordon Ross t->tqent_next = tq->tq_task.tqent_next;
169b819cea2SGordon Ross t->tqent_prev = &tq->tq_task;
170b819cea2SGordon Ross } else {
171b819cea2SGordon Ross t->tqent_next = &tq->tq_task;
172b819cea2SGordon Ross t->tqent_prev = tq->tq_task.tqent_prev;
173b819cea2SGordon Ross }
174b819cea2SGordon Ross t->tqent_next->tqent_prev = t;
175b819cea2SGordon Ross t->tqent_prev->tqent_next = t;
176b819cea2SGordon Ross t->tqent_func = func;
177b819cea2SGordon Ross t->tqent_arg = arg;
178b819cea2SGordon Ross t->tqent_flags = 0;
179b819cea2SGordon Ross cv_signal(&tq->tq_dispatch_cv);
180b819cea2SGordon Ross mutex_exit(&tq->tq_lock);
181b819cea2SGordon Ross return (1);
182b819cea2SGordon Ross }
183b819cea2SGordon Ross
184b819cea2SGordon Ross void
taskq_dispatch_ent(taskq_t * tq,task_func_t func,void * arg,uint_t flags,taskq_ent_t * t)185b819cea2SGordon Ross taskq_dispatch_ent(taskq_t *tq, task_func_t func, void *arg, uint_t flags,
186b819cea2SGordon Ross taskq_ent_t *t)
187b819cea2SGordon Ross {
188b819cea2SGordon Ross ASSERT(func != NULL);
189b819cea2SGordon Ross ASSERT(!(tq->tq_flags & TASKQ_DYNAMIC));
190b819cea2SGordon Ross
191b819cea2SGordon Ross /*
192b819cea2SGordon Ross * Mark it as a prealloc'd task. This is important
193b819cea2SGordon Ross * to ensure that we don't free it later.
194b819cea2SGordon Ross */
195b819cea2SGordon Ross t->tqent_flags |= TQENT_FLAG_PREALLOC;
196b819cea2SGordon Ross /*
197b819cea2SGordon Ross * Enqueue the task to the underlying queue.
198b819cea2SGordon Ross */
199b819cea2SGordon Ross mutex_enter(&tq->tq_lock);
200b819cea2SGordon Ross
201b819cea2SGordon Ross if (flags & TQ_FRONT) {
202b819cea2SGordon Ross t->tqent_next = tq->tq_task.tqent_next;
203b819cea2SGordon Ross t->tqent_prev = &tq->tq_task;
204b819cea2SGordon Ross } else {
205b819cea2SGordon Ross t->tqent_next = &tq->tq_task;
206b819cea2SGordon Ross t->tqent_prev = tq->tq_task.tqent_prev;
207b819cea2SGordon Ross }
208b819cea2SGordon Ross t->tqent_next->tqent_prev = t;
209b819cea2SGordon Ross t->tqent_prev->tqent_next = t;
210b819cea2SGordon Ross t->tqent_func = func;
211b819cea2SGordon Ross t->tqent_arg = arg;
212b819cea2SGordon Ross cv_signal(&tq->tq_dispatch_cv);
213b819cea2SGordon Ross mutex_exit(&tq->tq_lock);
214b819cea2SGordon Ross }
215b819cea2SGordon Ross
2164c99ecc3STim Kordas boolean_t
taskq_empty(taskq_t * tq)2174c99ecc3STim Kordas taskq_empty(taskq_t *tq)
2184c99ecc3STim Kordas {
2194c99ecc3STim Kordas boolean_t rv;
2204c99ecc3STim Kordas
2214c99ecc3STim Kordas mutex_enter(&tq->tq_lock);
2224c99ecc3STim Kordas rv = (tq->tq_task.tqent_next == &tq->tq_task) && (tq->tq_active == 0);
2234c99ecc3STim Kordas mutex_exit(&tq->tq_lock);
2244c99ecc3STim Kordas
2254c99ecc3STim Kordas return (rv);
2264c99ecc3STim Kordas }
2274c99ecc3STim Kordas
228b819cea2SGordon Ross void
taskq_wait(taskq_t * tq)229b819cea2SGordon Ross taskq_wait(taskq_t *tq)
230b819cea2SGordon Ross {
231b819cea2SGordon Ross mutex_enter(&tq->tq_lock);
232b819cea2SGordon Ross while (tq->tq_task.tqent_next != &tq->tq_task || tq->tq_active != 0)
233b819cea2SGordon Ross cv_wait(&tq->tq_wait_cv, &tq->tq_lock);
234b819cea2SGordon Ross mutex_exit(&tq->tq_lock);
235b819cea2SGordon Ross }
236b819cea2SGordon Ross
237*a3874b8bSToomas Soome void
taskq_wait_id(taskq_t * tq,taskqid_t id __unused)238*a3874b8bSToomas Soome taskq_wait_id(taskq_t *tq, taskqid_t id __unused)
239*a3874b8bSToomas Soome {
240*a3874b8bSToomas Soome taskq_wait(tq);
241*a3874b8bSToomas Soome }
242*a3874b8bSToomas Soome
243b819cea2SGordon Ross static void *
taskq_thread(void * arg)244b819cea2SGordon Ross taskq_thread(void *arg)
245b819cea2SGordon Ross {
246b819cea2SGordon Ross taskq_t *tq = arg;
247b819cea2SGordon Ross taskq_ent_t *t;
248b819cea2SGordon Ross boolean_t prealloc;
249b819cea2SGordon Ross
250b819cea2SGordon Ross mutex_enter(&tq->tq_lock);
251b819cea2SGordon Ross while (tq->tq_flags & TASKQ_ACTIVE) {
252b819cea2SGordon Ross if ((t = tq->tq_task.tqent_next) == &tq->tq_task) {
253b819cea2SGordon Ross if (--tq->tq_active == 0)
254b819cea2SGordon Ross cv_broadcast(&tq->tq_wait_cv);
255b819cea2SGordon Ross cv_wait(&tq->tq_dispatch_cv, &tq->tq_lock);
256b819cea2SGordon Ross tq->tq_active++;
257b819cea2SGordon Ross continue;
258b819cea2SGordon Ross }
259b819cea2SGordon Ross t->tqent_prev->tqent_next = t->tqent_next;
260b819cea2SGordon Ross t->tqent_next->tqent_prev = t->tqent_prev;
261b819cea2SGordon Ross t->tqent_next = NULL;
262b819cea2SGordon Ross t->tqent_prev = NULL;
263b819cea2SGordon Ross prealloc = t->tqent_flags & TQENT_FLAG_PREALLOC;
264b819cea2SGordon Ross mutex_exit(&tq->tq_lock);
265b819cea2SGordon Ross
266b819cea2SGordon Ross rw_enter(&tq->tq_threadlock, RW_READER);
267b819cea2SGordon Ross t->tqent_func(t->tqent_arg);
268b819cea2SGordon Ross rw_exit(&tq->tq_threadlock);
269b819cea2SGordon Ross
270b819cea2SGordon Ross mutex_enter(&tq->tq_lock);
271b819cea2SGordon Ross if (!prealloc)
272b819cea2SGordon Ross task_free(tq, t);
273b819cea2SGordon Ross }
274b819cea2SGordon Ross tq->tq_nthreads--;
275b819cea2SGordon Ross cv_broadcast(&tq->tq_wait_cv);
276b819cea2SGordon Ross mutex_exit(&tq->tq_lock);
277b819cea2SGordon Ross return (NULL);
278b819cea2SGordon Ross }
279b819cea2SGordon Ross
280b819cea2SGordon Ross /*ARGSUSED*/
281b819cea2SGordon Ross taskq_t *
taskq_create(const char * name,int nthr,pri_t pri,int minalloc,int maxalloc,uint_t flags)282b819cea2SGordon Ross taskq_create(const char *name, int nthr, pri_t pri, int minalloc,
283b819cea2SGordon Ross int maxalloc, uint_t flags)
284b819cea2SGordon Ross {
285b819cea2SGordon Ross return (taskq_create_proc(name, nthr, pri,
286b819cea2SGordon Ross minalloc, maxalloc, NULL, flags));
287b819cea2SGordon Ross }
288b819cea2SGordon Ross
289b819cea2SGordon Ross /*ARGSUSED*/
290b819cea2SGordon Ross taskq_t *
taskq_create_sysdc(const char * name,int nthr,int minalloc,int maxalloc,proc_t * proc,uint_t dc,uint_t flags)291f06dce2cSAndrew Stormont taskq_create_sysdc(const char *name, int nthr, int minalloc,
292f06dce2cSAndrew Stormont int maxalloc, proc_t *proc, uint_t dc, uint_t flags)
293f06dce2cSAndrew Stormont {
294f06dce2cSAndrew Stormont return (taskq_create_proc(name, nthr, maxclsyspri,
295f06dce2cSAndrew Stormont minalloc, maxalloc, proc, flags));
296f06dce2cSAndrew Stormont }
297f06dce2cSAndrew Stormont
298f06dce2cSAndrew Stormont /*ARGSUSED*/
299f06dce2cSAndrew Stormont taskq_t *
taskq_create_proc(const char * name,int nthreads,pri_t pri,int minalloc,int maxalloc,proc_t * proc,uint_t flags)300b819cea2SGordon Ross taskq_create_proc(const char *name, int nthreads, pri_t pri,
301b819cea2SGordon Ross int minalloc, int maxalloc, proc_t *proc, uint_t flags)
302b819cea2SGordon Ross {
303b819cea2SGordon Ross taskq_t *tq = kmem_zalloc(sizeof (taskq_t), KM_SLEEP);
304b819cea2SGordon Ross int t;
305b819cea2SGordon Ross
306b819cea2SGordon Ross if (flags & TASKQ_THREADS_CPU_PCT) {
307b819cea2SGordon Ross int pct;
308b819cea2SGordon Ross ASSERT3S(nthreads, >=, 0);
309b819cea2SGordon Ross ASSERT3S(nthreads, <=, 100);
310b819cea2SGordon Ross pct = MIN(nthreads, 100);
311b819cea2SGordon Ross pct = MAX(pct, 0);
312b819cea2SGordon Ross
313b819cea2SGordon Ross nthreads = (sysconf(_SC_NPROCESSORS_ONLN) * pct) / 100;
314b819cea2SGordon Ross nthreads = MAX(nthreads, 1); /* need at least 1 thread */
315b819cea2SGordon Ross } else {
316b819cea2SGordon Ross ASSERT3S(nthreads, >=, 1);
317b819cea2SGordon Ross }
318b819cea2SGordon Ross
319b819cea2SGordon Ross rw_init(&tq->tq_threadlock, NULL, RW_DEFAULT, NULL);
320b819cea2SGordon Ross mutex_init(&tq->tq_lock, NULL, MUTEX_DEFAULT, NULL);
321b819cea2SGordon Ross cv_init(&tq->tq_dispatch_cv, NULL, CV_DEFAULT, NULL);
322b819cea2SGordon Ross cv_init(&tq->tq_wait_cv, NULL, CV_DEFAULT, NULL);
323b819cea2SGordon Ross cv_init(&tq->tq_maxalloc_cv, NULL, CV_DEFAULT, NULL);
324b819cea2SGordon Ross tq->tq_flags = flags | TASKQ_ACTIVE;
325b819cea2SGordon Ross tq->tq_active = nthreads;
326b819cea2SGordon Ross tq->tq_nthreads = nthreads;
327b819cea2SGordon Ross tq->tq_minalloc = minalloc;
328b819cea2SGordon Ross tq->tq_maxalloc = maxalloc;
329b819cea2SGordon Ross tq->tq_task.tqent_next = &tq->tq_task;
330b819cea2SGordon Ross tq->tq_task.tqent_prev = &tq->tq_task;
331b819cea2SGordon Ross tq->tq_threadlist = kmem_alloc(nthreads * sizeof (thread_t), KM_SLEEP);
332b819cea2SGordon Ross
333b819cea2SGordon Ross if (flags & TASKQ_PREPOPULATE) {
334b819cea2SGordon Ross mutex_enter(&tq->tq_lock);
335b819cea2SGordon Ross while (minalloc-- > 0)
336b819cea2SGordon Ross task_free(tq, task_alloc(tq, KM_SLEEP));
337b819cea2SGordon Ross mutex_exit(&tq->tq_lock);
338b819cea2SGordon Ross }
339b819cea2SGordon Ross
340b819cea2SGordon Ross for (t = 0; t < nthreads; t++)
341b819cea2SGordon Ross (void) thr_create(0, 0, taskq_thread,
342b819cea2SGordon Ross tq, THR_BOUND, &tq->tq_threadlist[t]);
343b819cea2SGordon Ross
344b819cea2SGordon Ross return (tq);
345b819cea2SGordon Ross }
346b819cea2SGordon Ross
347b819cea2SGordon Ross void
taskq_destroy(taskq_t * tq)348b819cea2SGordon Ross taskq_destroy(taskq_t *tq)
349b819cea2SGordon Ross {
350b819cea2SGordon Ross int t;
351b819cea2SGordon Ross int nthreads = tq->tq_nthreads;
352b819cea2SGordon Ross
353b819cea2SGordon Ross taskq_wait(tq);
354b819cea2SGordon Ross
355b819cea2SGordon Ross mutex_enter(&tq->tq_lock);
356b819cea2SGordon Ross
357b819cea2SGordon Ross tq->tq_flags &= ~TASKQ_ACTIVE;
358b819cea2SGordon Ross cv_broadcast(&tq->tq_dispatch_cv);
359b819cea2SGordon Ross
360b819cea2SGordon Ross while (tq->tq_nthreads != 0)
361b819cea2SGordon Ross cv_wait(&tq->tq_wait_cv, &tq->tq_lock);
362b819cea2SGordon Ross
363b819cea2SGordon Ross tq->tq_minalloc = 0;
364b819cea2SGordon Ross while (tq->tq_nalloc != 0) {
365b819cea2SGordon Ross ASSERT(tq->tq_freelist != NULL);
366b819cea2SGordon Ross task_free(tq, task_alloc(tq, KM_SLEEP));
367b819cea2SGordon Ross }
368b819cea2SGordon Ross
369b819cea2SGordon Ross mutex_exit(&tq->tq_lock);
370b819cea2SGordon Ross
371b819cea2SGordon Ross for (t = 0; t < nthreads; t++)
372b819cea2SGordon Ross (void) thr_join(tq->tq_threadlist[t], NULL, NULL);
373b819cea2SGordon Ross
374b819cea2SGordon Ross kmem_free(tq->tq_threadlist, nthreads * sizeof (thread_t));
375b819cea2SGordon Ross
376b819cea2SGordon Ross rw_destroy(&tq->tq_threadlock);
377b819cea2SGordon Ross mutex_destroy(&tq->tq_lock);
378b819cea2SGordon Ross cv_destroy(&tq->tq_dispatch_cv);
379b819cea2SGordon Ross cv_destroy(&tq->tq_wait_cv);
380b819cea2SGordon Ross cv_destroy(&tq->tq_maxalloc_cv);
381b819cea2SGordon Ross
382b819cea2SGordon Ross kmem_free(tq, sizeof (taskq_t));
383b819cea2SGordon Ross }
384b819cea2SGordon Ross
385b819cea2SGordon Ross int
taskq_member(taskq_t * tq,struct _kthread * t)386b819cea2SGordon Ross taskq_member(taskq_t *tq, struct _kthread *t)
387b819cea2SGordon Ross {
388b819cea2SGordon Ross int i;
389b819cea2SGordon Ross
390b819cea2SGordon Ross if (taskq_now)
391b819cea2SGordon Ross return (1);
392b819cea2SGordon Ross
393b819cea2SGordon Ross for (i = 0; i < tq->tq_nthreads; i++)
394b819cea2SGordon Ross if (tq->tq_threadlist[i] == (thread_t)(uintptr_t)t)
395b819cea2SGordon Ross return (1);
396b819cea2SGordon Ross
397b819cea2SGordon Ross return (0);
398b819cea2SGordon Ross }
399b819cea2SGordon Ross
400b819cea2SGordon Ross void
system_taskq_init(void)401b819cea2SGordon Ross system_taskq_init(void)
402b819cea2SGordon Ross {
403b819cea2SGordon Ross system_taskq = taskq_create("system_taskq", 64, minclsyspri, 4, 512,
404b819cea2SGordon Ross TASKQ_DYNAMIC | TASKQ_PREPOPULATE);
405b819cea2SGordon Ross }
406b819cea2SGordon Ross
407b819cea2SGordon Ross void
system_taskq_fini(void)408b819cea2SGordon Ross system_taskq_fini(void)
409b819cea2SGordon Ross {
410b819cea2SGordon Ross taskq_destroy(system_taskq);
411b819cea2SGordon Ross system_taskq = NULL; /* defensive */
412b819cea2SGordon Ross }
413