xref: /illumos-gate/usr/src/lib/libfakekernel/common/taskq.c (revision 4c99ecc308d297ccc23eec0665e892052c57bf49)
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.
29*4c99ecc3STim 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 *
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) {
103b819cea2SGordon Ross 			if (!(tqflags & KM_SLEEP))
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
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
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);
165b819cea2SGordon Ross 		return (0);
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
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 
216*4c99ecc3STim Kordas boolean_t
217*4c99ecc3STim Kordas taskq_empty(taskq_t *tq)
218*4c99ecc3STim Kordas {
219*4c99ecc3STim Kordas 	boolean_t rv;
220*4c99ecc3STim Kordas 
221*4c99ecc3STim Kordas 	mutex_enter(&tq->tq_lock);
222*4c99ecc3STim Kordas 	rv = (tq->tq_task.tqent_next == &tq->tq_task) && (tq->tq_active == 0);
223*4c99ecc3STim Kordas 	mutex_exit(&tq->tq_lock);
224*4c99ecc3STim Kordas 
225*4c99ecc3STim Kordas 	return (rv);
226*4c99ecc3STim Kordas }
227*4c99ecc3STim Kordas 
228b819cea2SGordon Ross void
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 
237b819cea2SGordon Ross static void *
238b819cea2SGordon Ross taskq_thread(void *arg)
239b819cea2SGordon Ross {
240b819cea2SGordon Ross 	taskq_t *tq = arg;
241b819cea2SGordon Ross 	taskq_ent_t *t;
242b819cea2SGordon Ross 	boolean_t prealloc;
243b819cea2SGordon Ross 
244b819cea2SGordon Ross 	mutex_enter(&tq->tq_lock);
245b819cea2SGordon Ross 	while (tq->tq_flags & TASKQ_ACTIVE) {
246b819cea2SGordon Ross 		if ((t = tq->tq_task.tqent_next) == &tq->tq_task) {
247b819cea2SGordon Ross 			if (--tq->tq_active == 0)
248b819cea2SGordon Ross 				cv_broadcast(&tq->tq_wait_cv);
249b819cea2SGordon Ross 			cv_wait(&tq->tq_dispatch_cv, &tq->tq_lock);
250b819cea2SGordon Ross 			tq->tq_active++;
251b819cea2SGordon Ross 			continue;
252b819cea2SGordon Ross 		}
253b819cea2SGordon Ross 		t->tqent_prev->tqent_next = t->tqent_next;
254b819cea2SGordon Ross 		t->tqent_next->tqent_prev = t->tqent_prev;
255b819cea2SGordon Ross 		t->tqent_next = NULL;
256b819cea2SGordon Ross 		t->tqent_prev = NULL;
257b819cea2SGordon Ross 		prealloc = t->tqent_flags & TQENT_FLAG_PREALLOC;
258b819cea2SGordon Ross 		mutex_exit(&tq->tq_lock);
259b819cea2SGordon Ross 
260b819cea2SGordon Ross 		rw_enter(&tq->tq_threadlock, RW_READER);
261b819cea2SGordon Ross 		t->tqent_func(t->tqent_arg);
262b819cea2SGordon Ross 		rw_exit(&tq->tq_threadlock);
263b819cea2SGordon Ross 
264b819cea2SGordon Ross 		mutex_enter(&tq->tq_lock);
265b819cea2SGordon Ross 		if (!prealloc)
266b819cea2SGordon Ross 			task_free(tq, t);
267b819cea2SGordon Ross 	}
268b819cea2SGordon Ross 	tq->tq_nthreads--;
269b819cea2SGordon Ross 	cv_broadcast(&tq->tq_wait_cv);
270b819cea2SGordon Ross 	mutex_exit(&tq->tq_lock);
271b819cea2SGordon Ross 	return (NULL);
272b819cea2SGordon Ross }
273b819cea2SGordon Ross 
274b819cea2SGordon Ross /*ARGSUSED*/
275b819cea2SGordon Ross taskq_t *
276b819cea2SGordon Ross taskq_create(const char *name, int nthr, pri_t pri, int minalloc,
277b819cea2SGordon Ross     int maxalloc, uint_t flags)
278b819cea2SGordon Ross {
279b819cea2SGordon Ross 	return (taskq_create_proc(name, nthr, pri,
280b819cea2SGordon Ross 	    minalloc, maxalloc, NULL, flags));
281b819cea2SGordon Ross }
282b819cea2SGordon Ross 
283f06dce2cSAndrew Stormont /*ARGSUSED*/
284f06dce2cSAndrew Stormont taskq_t *
285f06dce2cSAndrew Stormont taskq_create_sysdc(const char *name, int nthr, int minalloc,
286f06dce2cSAndrew Stormont     int maxalloc, proc_t *proc, uint_t dc, uint_t flags)
287f06dce2cSAndrew Stormont {
288f06dce2cSAndrew Stormont 	return (taskq_create_proc(name, nthr, maxclsyspri,
289f06dce2cSAndrew Stormont 	    minalloc, maxalloc, proc, flags));
290f06dce2cSAndrew Stormont }
291f06dce2cSAndrew Stormont 
292b819cea2SGordon Ross /*ARGSUSED*/
293b819cea2SGordon Ross taskq_t *
294b819cea2SGordon Ross taskq_create_proc(const char *name, int nthreads, pri_t pri,
295f06dce2cSAndrew Stormont     int minalloc, int maxalloc, proc_t *proc, uint_t flags)
296b819cea2SGordon Ross {
297b819cea2SGordon Ross 	taskq_t *tq = kmem_zalloc(sizeof (taskq_t), KM_SLEEP);
298b819cea2SGordon Ross 	int t;
299b819cea2SGordon Ross 
300b819cea2SGordon Ross 	if (flags & TASKQ_THREADS_CPU_PCT) {
301b819cea2SGordon Ross 		int pct;
302b819cea2SGordon Ross 		ASSERT3S(nthreads, >=, 0);
303b819cea2SGordon Ross 		ASSERT3S(nthreads, <=, 100);
304b819cea2SGordon Ross 		pct = MIN(nthreads, 100);
305b819cea2SGordon Ross 		pct = MAX(pct, 0);
306b819cea2SGordon Ross 
307b819cea2SGordon Ross 		nthreads = (sysconf(_SC_NPROCESSORS_ONLN) * pct) / 100;
308b819cea2SGordon Ross 		nthreads = MAX(nthreads, 1);	/* need at least 1 thread */
309b819cea2SGordon Ross 	} else {
310b819cea2SGordon Ross 		ASSERT3S(nthreads, >=, 1);
311b819cea2SGordon Ross 	}
312b819cea2SGordon Ross 
313b819cea2SGordon Ross 	rw_init(&tq->tq_threadlock, NULL, RW_DEFAULT, NULL);
314b819cea2SGordon Ross 	mutex_init(&tq->tq_lock, NULL, MUTEX_DEFAULT, NULL);
315b819cea2SGordon Ross 	cv_init(&tq->tq_dispatch_cv, NULL, CV_DEFAULT, NULL);
316b819cea2SGordon Ross 	cv_init(&tq->tq_wait_cv, NULL, CV_DEFAULT, NULL);
317b819cea2SGordon Ross 	cv_init(&tq->tq_maxalloc_cv, NULL, CV_DEFAULT, NULL);
318b819cea2SGordon Ross 	tq->tq_flags = flags | TASKQ_ACTIVE;
319b819cea2SGordon Ross 	tq->tq_active = nthreads;
320b819cea2SGordon Ross 	tq->tq_nthreads = nthreads;
321b819cea2SGordon Ross 	tq->tq_minalloc = minalloc;
322b819cea2SGordon Ross 	tq->tq_maxalloc = maxalloc;
323b819cea2SGordon Ross 	tq->tq_task.tqent_next = &tq->tq_task;
324b819cea2SGordon Ross 	tq->tq_task.tqent_prev = &tq->tq_task;
325b819cea2SGordon Ross 	tq->tq_threadlist = kmem_alloc(nthreads * sizeof (thread_t), KM_SLEEP);
326b819cea2SGordon Ross 
327b819cea2SGordon Ross 	if (flags & TASKQ_PREPOPULATE) {
328b819cea2SGordon Ross 		mutex_enter(&tq->tq_lock);
329b819cea2SGordon Ross 		while (minalloc-- > 0)
330b819cea2SGordon Ross 			task_free(tq, task_alloc(tq, KM_SLEEP));
331b819cea2SGordon Ross 		mutex_exit(&tq->tq_lock);
332b819cea2SGordon Ross 	}
333b819cea2SGordon Ross 
334b819cea2SGordon Ross 	for (t = 0; t < nthreads; t++)
335b819cea2SGordon Ross 		(void) thr_create(0, 0, taskq_thread,
336b819cea2SGordon Ross 		    tq, THR_BOUND, &tq->tq_threadlist[t]);
337b819cea2SGordon Ross 
338b819cea2SGordon Ross 	return (tq);
339b819cea2SGordon Ross }
340b819cea2SGordon Ross 
341b819cea2SGordon Ross void
342b819cea2SGordon Ross taskq_destroy(taskq_t *tq)
343b819cea2SGordon Ross {
344b819cea2SGordon Ross 	int t;
345b819cea2SGordon Ross 	int nthreads = tq->tq_nthreads;
346b819cea2SGordon Ross 
347b819cea2SGordon Ross 	taskq_wait(tq);
348b819cea2SGordon Ross 
349b819cea2SGordon Ross 	mutex_enter(&tq->tq_lock);
350b819cea2SGordon Ross 
351b819cea2SGordon Ross 	tq->tq_flags &= ~TASKQ_ACTIVE;
352b819cea2SGordon Ross 	cv_broadcast(&tq->tq_dispatch_cv);
353b819cea2SGordon Ross 
354b819cea2SGordon Ross 	while (tq->tq_nthreads != 0)
355b819cea2SGordon Ross 		cv_wait(&tq->tq_wait_cv, &tq->tq_lock);
356b819cea2SGordon Ross 
357b819cea2SGordon Ross 	tq->tq_minalloc = 0;
358b819cea2SGordon Ross 	while (tq->tq_nalloc != 0) {
359b819cea2SGordon Ross 		ASSERT(tq->tq_freelist != NULL);
360b819cea2SGordon Ross 		task_free(tq, task_alloc(tq, KM_SLEEP));
361b819cea2SGordon Ross 	}
362b819cea2SGordon Ross 
363b819cea2SGordon Ross 	mutex_exit(&tq->tq_lock);
364b819cea2SGordon Ross 
365b819cea2SGordon Ross 	for (t = 0; t < nthreads; t++)
366b819cea2SGordon Ross 		(void) thr_join(tq->tq_threadlist[t], NULL, NULL);
367b819cea2SGordon Ross 
368b819cea2SGordon Ross 	kmem_free(tq->tq_threadlist, nthreads * sizeof (thread_t));
369b819cea2SGordon Ross 
370b819cea2SGordon Ross 	rw_destroy(&tq->tq_threadlock);
371b819cea2SGordon Ross 	mutex_destroy(&tq->tq_lock);
372b819cea2SGordon Ross 	cv_destroy(&tq->tq_dispatch_cv);
373b819cea2SGordon Ross 	cv_destroy(&tq->tq_wait_cv);
374b819cea2SGordon Ross 	cv_destroy(&tq->tq_maxalloc_cv);
375b819cea2SGordon Ross 
376b819cea2SGordon Ross 	kmem_free(tq, sizeof (taskq_t));
377b819cea2SGordon Ross }
378b819cea2SGordon Ross 
379b819cea2SGordon Ross int
380b819cea2SGordon Ross taskq_member(taskq_t *tq, struct _kthread *t)
381b819cea2SGordon Ross {
382b819cea2SGordon Ross 	int i;
383b819cea2SGordon Ross 
384b819cea2SGordon Ross 	if (taskq_now)
385b819cea2SGordon Ross 		return (1);
386b819cea2SGordon Ross 
387b819cea2SGordon Ross 	for (i = 0; i < tq->tq_nthreads; i++)
388b819cea2SGordon Ross 		if (tq->tq_threadlist[i] == (thread_t)(uintptr_t)t)
389b819cea2SGordon Ross 			return (1);
390b819cea2SGordon Ross 
391b819cea2SGordon Ross 	return (0);
392b819cea2SGordon Ross }
393b819cea2SGordon Ross 
394b819cea2SGordon Ross void
395b819cea2SGordon Ross system_taskq_init(void)
396b819cea2SGordon Ross {
397b819cea2SGordon Ross 	system_taskq = taskq_create("system_taskq", 64, minclsyspri, 4, 512,
398b819cea2SGordon Ross 	    TASKQ_DYNAMIC | TASKQ_PREPOPULATE);
399b819cea2SGordon Ross }
400b819cea2SGordon Ross 
401b819cea2SGordon Ross void
402b819cea2SGordon Ross system_taskq_fini(void)
403b819cea2SGordon Ross {
404b819cea2SGordon Ross 	taskq_destroy(system_taskq);
405b819cea2SGordon Ross 	system_taskq = NULL; /* defensive */
406b819cea2SGordon Ross }
407