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