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 
289f06dce2cSAndrew Stormont /*ARGSUSED*/
290f06dce2cSAndrew Stormont 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 
298b819cea2SGordon Ross /*ARGSUSED*/
299b819cea2SGordon Ross 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,
301f06dce2cSAndrew Stormont     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