xref: /onnv-gate/usr/src/uts/common/avs/ns/solaris/nsc_thread.c (revision 9093:cd587b0bd19c)
17836SJohn.Forte@Sun.COM /*
27836SJohn.Forte@Sun.COM  * CDDL HEADER START
37836SJohn.Forte@Sun.COM  *
47836SJohn.Forte@Sun.COM  * The contents of this file are subject to the terms of the
57836SJohn.Forte@Sun.COM  * Common Development and Distribution License (the "License").
67836SJohn.Forte@Sun.COM  * You may not use this file except in compliance with the License.
77836SJohn.Forte@Sun.COM  *
87836SJohn.Forte@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97836SJohn.Forte@Sun.COM  * or http://www.opensolaris.org/os/licensing.
107836SJohn.Forte@Sun.COM  * See the License for the specific language governing permissions
117836SJohn.Forte@Sun.COM  * and limitations under the License.
127836SJohn.Forte@Sun.COM  *
137836SJohn.Forte@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
147836SJohn.Forte@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157836SJohn.Forte@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
167836SJohn.Forte@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
177836SJohn.Forte@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
187836SJohn.Forte@Sun.COM  *
197836SJohn.Forte@Sun.COM  * CDDL HEADER END
207836SJohn.Forte@Sun.COM  */
217836SJohn.Forte@Sun.COM /*
22*9093SRamana.Srikanth@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237836SJohn.Forte@Sun.COM  * Use is subject to license terms.
247836SJohn.Forte@Sun.COM  */
257836SJohn.Forte@Sun.COM 
267836SJohn.Forte@Sun.COM #include <sys/types.h>
277836SJohn.Forte@Sun.COM #include <sys/debug.h>
287836SJohn.Forte@Sun.COM #include <sys/ksynch.h>
297836SJohn.Forte@Sun.COM #include <sys/cmn_err.h>
307836SJohn.Forte@Sun.COM #include <sys/kmem.h>
317836SJohn.Forte@Sun.COM #include <sys/ddi.h>
327836SJohn.Forte@Sun.COM #include <sys/errno.h>
337836SJohn.Forte@Sun.COM #include "nsc_thread.h"
347836SJohn.Forte@Sun.COM 
357836SJohn.Forte@Sun.COM #ifdef DS_DDICT
367836SJohn.Forte@Sun.COM #include "../contract.h"
377836SJohn.Forte@Sun.COM #endif
387836SJohn.Forte@Sun.COM 
397836SJohn.Forte@Sun.COM #include "../nsctl.h"
407836SJohn.Forte@Sun.COM #include "nskernd.h"
417836SJohn.Forte@Sun.COM #include <sys/nsctl/nsctl.h>
427836SJohn.Forte@Sun.COM 
437836SJohn.Forte@Sun.COM #include <sys/sdt.h>		/* dtrace is S10 or later */
447836SJohn.Forte@Sun.COM 
457836SJohn.Forte@Sun.COM 
467836SJohn.Forte@Sun.COM /*
477836SJohn.Forte@Sun.COM  * Global data
487836SJohn.Forte@Sun.COM  */
497836SJohn.Forte@Sun.COM static nstset_t		*nst_sets;
507836SJohn.Forte@Sun.COM static nsthread_t	*nst_pending;
517836SJohn.Forte@Sun.COM static kmutex_t		nst_global_lock;	/* nst_sets, nst_pending */
527836SJohn.Forte@Sun.COM 
537836SJohn.Forte@Sun.COM 
547836SJohn.Forte@Sun.COM /*
557836SJohn.Forte@Sun.COM  * nst_kmem_xalloc
567836SJohn.Forte@Sun.COM  *
577836SJohn.Forte@Sun.COM  * Poll for memory.
587836SJohn.Forte@Sun.COM  */
597836SJohn.Forte@Sun.COM static void *
nst_kmem_xalloc(size_t size,int sec,void * (* alloc)(size_t,int))607836SJohn.Forte@Sun.COM nst_kmem_xalloc(size_t size, int sec, void *(*alloc)(size_t, int))
617836SJohn.Forte@Sun.COM {
627836SJohn.Forte@Sun.COM 	clock_t usec = sec * 1000000;
637836SJohn.Forte@Sun.COM 	void *p = NULL;
647836SJohn.Forte@Sun.COM 
657836SJohn.Forte@Sun.COM 	while (usec > 0) {
667836SJohn.Forte@Sun.COM 		if ((p = (*alloc)(size, KM_NOSLEEP)) != NULL)
677836SJohn.Forte@Sun.COM 			return (p);
687836SJohn.Forte@Sun.COM 
697836SJohn.Forte@Sun.COM 		delay(drv_usectohz((clock_t)NST_MEMORY_TIMEOUT));
707836SJohn.Forte@Sun.COM 		usec -= NST_MEMORY_TIMEOUT;
717836SJohn.Forte@Sun.COM 	}
727836SJohn.Forte@Sun.COM 
73*9093SRamana.Srikanth@Sun.COM 	cmn_err(CE_WARN, "!nst_kmem_xalloc: failed to alloc %ld bytes", size);
747836SJohn.Forte@Sun.COM 	return (NULL);
757836SJohn.Forte@Sun.COM }
767836SJohn.Forte@Sun.COM 
777836SJohn.Forte@Sun.COM 
787836SJohn.Forte@Sun.COM #if 0
797836SJohn.Forte@Sun.COM /* currently unused */
807836SJohn.Forte@Sun.COM static void *
817836SJohn.Forte@Sun.COM nst_kmem_alloc(size_t size, int sec)
827836SJohn.Forte@Sun.COM {
837836SJohn.Forte@Sun.COM 	return (nst_kmem_xalloc(size, sec, kmem_alloc));
847836SJohn.Forte@Sun.COM }
857836SJohn.Forte@Sun.COM #endif
867836SJohn.Forte@Sun.COM 
877836SJohn.Forte@Sun.COM 
887836SJohn.Forte@Sun.COM static void *
nst_kmem_zalloc(size_t size,int sec)897836SJohn.Forte@Sun.COM nst_kmem_zalloc(size_t size, int sec)
907836SJohn.Forte@Sun.COM {
917836SJohn.Forte@Sun.COM 	return (nst_kmem_xalloc(size, sec, kmem_zalloc));
927836SJohn.Forte@Sun.COM }
937836SJohn.Forte@Sun.COM 
947836SJohn.Forte@Sun.COM 
957836SJohn.Forte@Sun.COM /*
967836SJohn.Forte@Sun.COM  * Queue stuff that should be in the DDI.
977836SJohn.Forte@Sun.COM  */
987836SJohn.Forte@Sun.COM 
997836SJohn.Forte@Sun.COM /*
1007836SJohn.Forte@Sun.COM  * nst_insque
1017836SJohn.Forte@Sun.COM  *
1027836SJohn.Forte@Sun.COM  * Insert entryp after predp in a doubly linked list.
1037836SJohn.Forte@Sun.COM  */
1047836SJohn.Forte@Sun.COM static void
nst_insque(nst_q_t * entryp,nst_q_t * predp)1057836SJohn.Forte@Sun.COM nst_insque(nst_q_t *entryp, nst_q_t *predp)
1067836SJohn.Forte@Sun.COM {
1077836SJohn.Forte@Sun.COM 	entryp->q_back = predp;
1087836SJohn.Forte@Sun.COM 	entryp->q_forw = predp->q_forw;
1097836SJohn.Forte@Sun.COM 	predp->q_forw = entryp;
1107836SJohn.Forte@Sun.COM 	entryp->q_forw->q_back = entryp;
1117836SJohn.Forte@Sun.COM }
1127836SJohn.Forte@Sun.COM #ifndef DS_DDICT
1137836SJohn.Forte@Sun.COM #pragma inline(nst_insque)	/* compiler hint to inline this function */
1147836SJohn.Forte@Sun.COM #endif
1157836SJohn.Forte@Sun.COM 
1167836SJohn.Forte@Sun.COM 
1177836SJohn.Forte@Sun.COM /*
1187836SJohn.Forte@Sun.COM  * nst_remque
1197836SJohn.Forte@Sun.COM  *
1207836SJohn.Forte@Sun.COM  * Remove entryp from a doubly linked list.
1217836SJohn.Forte@Sun.COM  */
1227836SJohn.Forte@Sun.COM static void
nst_remque(nst_q_t * entryp)1237836SJohn.Forte@Sun.COM nst_remque(nst_q_t *entryp)
1247836SJohn.Forte@Sun.COM {
1257836SJohn.Forte@Sun.COM 	entryp->q_back->q_forw = entryp->q_forw;
1267836SJohn.Forte@Sun.COM 	entryp->q_forw->q_back = entryp->q_back;
1277836SJohn.Forte@Sun.COM 	entryp->q_forw = entryp->q_back = NULL;
1287836SJohn.Forte@Sun.COM }
1297836SJohn.Forte@Sun.COM #ifndef DS_DDICT
1307836SJohn.Forte@Sun.COM #pragma inline(nst_remque)	/* compiler hint to inline this function */
1317836SJohn.Forte@Sun.COM #endif
1327836SJohn.Forte@Sun.COM 
1337836SJohn.Forte@Sun.COM 
1347836SJohn.Forte@Sun.COM /*
1357836SJohn.Forte@Sun.COM  * nst_thread_init
1367836SJohn.Forte@Sun.COM  *
1377836SJohn.Forte@Sun.COM  * Initialise the dynamic part of a thread
1387836SJohn.Forte@Sun.COM  */
1397836SJohn.Forte@Sun.COM static void
nst_thread_init(nsthread_t * tp)1407836SJohn.Forte@Sun.COM nst_thread_init(nsthread_t *tp)
1417836SJohn.Forte@Sun.COM {
1427836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&((tp->tp_set)->set_lock)));
1437836SJohn.Forte@Sun.COM 	ASSERT(!(tp->tp_flag & NST_TF_INUSE));
1447836SJohn.Forte@Sun.COM 	tp->tp_flag = NST_TF_INUSE;
1457836SJohn.Forte@Sun.COM 	tp->tp_func = NULL;
1467836SJohn.Forte@Sun.COM 	tp->tp_arg = NULL;
1477836SJohn.Forte@Sun.COM }
1487836SJohn.Forte@Sun.COM #ifndef DS_DDICT
1497836SJohn.Forte@Sun.COM #pragma inline(nst_thread_init)	/* compiler hint to inline this function */
1507836SJohn.Forte@Sun.COM #endif
1517836SJohn.Forte@Sun.COM 
1527836SJohn.Forte@Sun.COM 
1537836SJohn.Forte@Sun.COM /*
1547836SJohn.Forte@Sun.COM  * nst_thread_alloc
1557836SJohn.Forte@Sun.COM  *
1567836SJohn.Forte@Sun.COM  * Return an nsthread from the free pool, NULL if none
1577836SJohn.Forte@Sun.COM  */
1587836SJohn.Forte@Sun.COM static nsthread_t *
nst_thread_alloc(nstset_t * set,const int sleep)1597836SJohn.Forte@Sun.COM nst_thread_alloc(nstset_t *set, const int sleep)
1607836SJohn.Forte@Sun.COM {
1617836SJohn.Forte@Sun.COM 	nsthread_t *tp = NULL;
1627836SJohn.Forte@Sun.COM 
1637836SJohn.Forte@Sun.COM 	mutex_enter(&set->set_lock);
1647836SJohn.Forte@Sun.COM 
1657836SJohn.Forte@Sun.COM 	if (set->set_flag & NST_SF_KILL) {
1667836SJohn.Forte@Sun.COM 		mutex_exit(&set->set_lock);
167*9093SRamana.Srikanth@Sun.COM 		DTRACE_PROBE1(nst_thread_alloc_err_kill, nstset_t *, set);
1687836SJohn.Forte@Sun.COM 		return (NULL);
1697836SJohn.Forte@Sun.COM 	}
1707836SJohn.Forte@Sun.COM 
1717836SJohn.Forte@Sun.COM 	do {
1727836SJohn.Forte@Sun.COM 		tp = (nsthread_t *)set->set_free.q_forw;
1737836SJohn.Forte@Sun.COM 		if (tp != (nsthread_t *)&set->set_free)
1747836SJohn.Forte@Sun.COM 			nst_remque(&tp->tp_link);
1757836SJohn.Forte@Sun.COM 		else {
1767836SJohn.Forte@Sun.COM 			tp = NULL;
1777836SJohn.Forte@Sun.COM 
1787836SJohn.Forte@Sun.COM 			if (!sleep)
1797836SJohn.Forte@Sun.COM 				break;
1807836SJohn.Forte@Sun.COM 
1817836SJohn.Forte@Sun.COM 			set->set_res_cnt++;
1827836SJohn.Forte@Sun.COM 
183*9093SRamana.Srikanth@Sun.COM 			DTRACE_PROBE2(nst_thread_alloc_sleep, nstset_t *, set,
184*9093SRamana.Srikanth@Sun.COM 			    int, set->set_res_cnt);
1857836SJohn.Forte@Sun.COM 
1867836SJohn.Forte@Sun.COM 			cv_wait(&set->set_res_cv, &set->set_lock);
1877836SJohn.Forte@Sun.COM 
188*9093SRamana.Srikanth@Sun.COM 			DTRACE_PROBE1(nst_thread_alloc_wake, nstset_t *, set);
1897836SJohn.Forte@Sun.COM 
1907836SJohn.Forte@Sun.COM 			set->set_res_cnt--;
1917836SJohn.Forte@Sun.COM 
1927836SJohn.Forte@Sun.COM 			if (set->set_flag & NST_SF_KILL)
1937836SJohn.Forte@Sun.COM 				break;
1947836SJohn.Forte@Sun.COM 		}
1957836SJohn.Forte@Sun.COM 	} while (tp == NULL);
1967836SJohn.Forte@Sun.COM 
1977836SJohn.Forte@Sun.COM 	/* initialise the thread */
1987836SJohn.Forte@Sun.COM 
1997836SJohn.Forte@Sun.COM 	if (tp != NULL) {
2007836SJohn.Forte@Sun.COM 		nst_thread_init(tp);
2017836SJohn.Forte@Sun.COM 		set->set_nlive++;
2027836SJohn.Forte@Sun.COM 	}
2037836SJohn.Forte@Sun.COM 
2047836SJohn.Forte@Sun.COM 	mutex_exit(&set->set_lock);
2057836SJohn.Forte@Sun.COM 
2067836SJohn.Forte@Sun.COM 	return (tp);
2077836SJohn.Forte@Sun.COM }
2087836SJohn.Forte@Sun.COM 
2097836SJohn.Forte@Sun.COM 
2107836SJohn.Forte@Sun.COM /*
2117836SJohn.Forte@Sun.COM  * nst_thread_free
2127836SJohn.Forte@Sun.COM  *
2137836SJohn.Forte@Sun.COM  * Requeue a thread on the free or reuse pools.  Threads are always
2147836SJohn.Forte@Sun.COM  * queued to the tail of the list to prevent rapid recycling.
2157836SJohn.Forte@Sun.COM  *
2167836SJohn.Forte@Sun.COM  * Must be called with set->set_lock held.
2177836SJohn.Forte@Sun.COM  */
2187836SJohn.Forte@Sun.COM static void
nst_thread_free(nsthread_t * tp)2197836SJohn.Forte@Sun.COM nst_thread_free(nsthread_t *tp)
2207836SJohn.Forte@Sun.COM {
2217836SJohn.Forte@Sun.COM 	nstset_t *set = tp->tp_set;
2227836SJohn.Forte@Sun.COM 
2237836SJohn.Forte@Sun.COM 	if (!set)
2247836SJohn.Forte@Sun.COM 		return;
2257836SJohn.Forte@Sun.COM 
2267836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&set->set_lock));
2277836SJohn.Forte@Sun.COM 
2287836SJohn.Forte@Sun.COM 	tp->tp_flag &= ~NST_TF_INUSE;
2297836SJohn.Forte@Sun.COM 	if (tp->tp_flag & NST_TF_DESTROY) {
2307836SJohn.Forte@Sun.COM 		/* add self to reuse pool */
2317836SJohn.Forte@Sun.COM 		nst_insque(&tp->tp_link, set->set_reuse.q_back);
2327836SJohn.Forte@Sun.COM 	} else {
2337836SJohn.Forte@Sun.COM 		/* add self to free pool */
2347836SJohn.Forte@Sun.COM 		nst_insque(&tp->tp_link, set->set_free.q_back);
2357836SJohn.Forte@Sun.COM 		if (set->set_res_cnt > 0)
2367836SJohn.Forte@Sun.COM 			cv_broadcast(&set->set_res_cv);
2377836SJohn.Forte@Sun.COM 	}
2387836SJohn.Forte@Sun.COM }
2397836SJohn.Forte@Sun.COM 
2407836SJohn.Forte@Sun.COM 
2417836SJohn.Forte@Sun.COM /*
2427836SJohn.Forte@Sun.COM  * nst_thread_run
2437836SJohn.Forte@Sun.COM  *
2447836SJohn.Forte@Sun.COM  * The first function that a new thread runs on entry from user land.
2457836SJohn.Forte@Sun.COM  * This is the main thread function that handles thread work and death.
2467836SJohn.Forte@Sun.COM  */
2477836SJohn.Forte@Sun.COM static void
nst_thread_run(void * arg)2487836SJohn.Forte@Sun.COM nst_thread_run(void *arg)
2497836SJohn.Forte@Sun.COM {
2507836SJohn.Forte@Sun.COM 	nsthread_t *tp;
2517836SJohn.Forte@Sun.COM 	nstset_t *set;
2527836SJohn.Forte@Sun.COM 	int first = 1;
2537836SJohn.Forte@Sun.COM 
2547836SJohn.Forte@Sun.COM 	mutex_enter(&nst_global_lock);
2557836SJohn.Forte@Sun.COM 
2567836SJohn.Forte@Sun.COM 	/* check if this thread is still on the pending list */
2577836SJohn.Forte@Sun.COM 
2587836SJohn.Forte@Sun.COM 	for (tp = nst_pending; tp; tp = tp->tp_chain) {
2597836SJohn.Forte@Sun.COM 		if (tp == (nsthread_t *)arg) {
2607836SJohn.Forte@Sun.COM 			break;
2617836SJohn.Forte@Sun.COM 		}
2627836SJohn.Forte@Sun.COM 	}
2637836SJohn.Forte@Sun.COM 
2647836SJohn.Forte@Sun.COM 	if (!tp) {
2657836SJohn.Forte@Sun.COM 		mutex_exit(&nst_global_lock);
2667836SJohn.Forte@Sun.COM 		return;
2677836SJohn.Forte@Sun.COM 	}
2687836SJohn.Forte@Sun.COM 
2697836SJohn.Forte@Sun.COM 	if (!tp->tp_set) {
2707836SJohn.Forte@Sun.COM 		mutex_exit(&nst_global_lock);
2717836SJohn.Forte@Sun.COM #ifdef DEBUG
272*9093SRamana.Srikanth@Sun.COM 		cmn_err(CE_WARN, "!nst_thread_run(%p): already dead?",
2737836SJohn.Forte@Sun.COM 		    (void *)tp);
2747836SJohn.Forte@Sun.COM #endif
2757836SJohn.Forte@Sun.COM 		return;
2767836SJohn.Forte@Sun.COM 	}
2777836SJohn.Forte@Sun.COM 
2787836SJohn.Forte@Sun.COM 	/* check that the set is still on the list of sets */
2797836SJohn.Forte@Sun.COM 
2807836SJohn.Forte@Sun.COM 	for (set = nst_sets; set; set = set->set_next) {
2817836SJohn.Forte@Sun.COM 		if (set == tp->tp_set) {
2827836SJohn.Forte@Sun.COM 			break;
2837836SJohn.Forte@Sun.COM 		}
2847836SJohn.Forte@Sun.COM 	}
2857836SJohn.Forte@Sun.COM 
2867836SJohn.Forte@Sun.COM 	if (!set) {
2877836SJohn.Forte@Sun.COM 		mutex_exit(&nst_global_lock);
2887836SJohn.Forte@Sun.COM #ifdef DEBUG
289*9093SRamana.Srikanth@Sun.COM 		cmn_err(CE_WARN, "!nst_thread_run(%p): no set?", (void *)tp);
2907836SJohn.Forte@Sun.COM #endif
2917836SJohn.Forte@Sun.COM 		return;
2927836SJohn.Forte@Sun.COM 	}
2937836SJohn.Forte@Sun.COM 
2947836SJohn.Forte@Sun.COM 	mutex_enter(&set->set_lock);
2957836SJohn.Forte@Sun.COM 
2967836SJohn.Forte@Sun.COM 	mutex_exit(&nst_global_lock);
2977836SJohn.Forte@Sun.COM 
2987836SJohn.Forte@Sun.COM 	/*
2997836SJohn.Forte@Sun.COM 	 * Mark the parent.
3007836SJohn.Forte@Sun.COM 	 * The parent won't actually run until set->set_lock is dropped.
3017836SJohn.Forte@Sun.COM 	 */
3027836SJohn.Forte@Sun.COM 
3037836SJohn.Forte@Sun.COM 	tp->tp_flag &= ~NST_TF_PENDING;
3047836SJohn.Forte@Sun.COM 	cv_broadcast(&tp->tp_cv);
3057836SJohn.Forte@Sun.COM 
3067836SJohn.Forte@Sun.COM 	/*
3077836SJohn.Forte@Sun.COM 	 * Main loop.
3087836SJohn.Forte@Sun.COM 	 */
3097836SJohn.Forte@Sun.COM 
3107836SJohn.Forte@Sun.COM 	while (!(set->set_flag & NST_SF_KILL) &&
3117836SJohn.Forte@Sun.COM 	    !(tp->tp_flag & NST_TF_KILL)) {
3127836SJohn.Forte@Sun.COM 		/*
3137836SJohn.Forte@Sun.COM 		 * On initial entry the caller will add this thread to
3147836SJohn.Forte@Sun.COM 		 * the free pool if required, there after the thread
3157836SJohn.Forte@Sun.COM 		 * must do it for itself.
3167836SJohn.Forte@Sun.COM 		 */
3177836SJohn.Forte@Sun.COM 
3187836SJohn.Forte@Sun.COM 		if (first) {
3197836SJohn.Forte@Sun.COM 			first = 0;
3207836SJohn.Forte@Sun.COM 		} else {
3217836SJohn.Forte@Sun.COM 			nst_thread_free(tp);
3227836SJohn.Forte@Sun.COM 			set->set_nlive--;
3237836SJohn.Forte@Sun.COM 		}
3247836SJohn.Forte@Sun.COM 
325*9093SRamana.Srikanth@Sun.COM 		DTRACE_PROBE1(nst_thread_run_sleep, nsthread_t *, tp);
3267836SJohn.Forte@Sun.COM 
3277836SJohn.Forte@Sun.COM 		cv_wait(&tp->tp_cv, &set->set_lock);
3287836SJohn.Forte@Sun.COM 
329*9093SRamana.Srikanth@Sun.COM 		DTRACE_PROBE1(nst_thread_run_wake, nsthread_t *, tp);
3307836SJohn.Forte@Sun.COM 
3317836SJohn.Forte@Sun.COM 		if ((set->set_flag & NST_SF_KILL) ||
3327836SJohn.Forte@Sun.COM 		    (tp->tp_flag & NST_TF_KILL)) {
3337836SJohn.Forte@Sun.COM 			break;
3347836SJohn.Forte@Sun.COM 		}
3357836SJohn.Forte@Sun.COM 
3367836SJohn.Forte@Sun.COM 		mutex_exit(&set->set_lock);
3377836SJohn.Forte@Sun.COM 
3387836SJohn.Forte@Sun.COM 		if (tp->tp_func) {
3397836SJohn.Forte@Sun.COM 			(*tp->tp_func)(tp->tp_arg);
3407836SJohn.Forte@Sun.COM 			tp->tp_func = 0;
3417836SJohn.Forte@Sun.COM 			tp->tp_arg = 0;
3427836SJohn.Forte@Sun.COM 		}
3437836SJohn.Forte@Sun.COM #ifdef DEBUG
3447836SJohn.Forte@Sun.COM 		else {
3457836SJohn.Forte@Sun.COM 			cmn_err(CE_WARN,
346*9093SRamana.Srikanth@Sun.COM 			    "!nst_thread_run(%p): NULL function pointer",
3477836SJohn.Forte@Sun.COM 			    (void *)tp);
3487836SJohn.Forte@Sun.COM 		}
3497836SJohn.Forte@Sun.COM #endif
3507836SJohn.Forte@Sun.COM 
3517836SJohn.Forte@Sun.COM 		mutex_enter(&set->set_lock);
3527836SJohn.Forte@Sun.COM 	}
3537836SJohn.Forte@Sun.COM 
3547836SJohn.Forte@Sun.COM 	/* remove self from the free and/or reuse pools */
3557836SJohn.Forte@Sun.COM 	if (tp->tp_link.q_forw != NULL || tp->tp_link.q_back != NULL) {
3567836SJohn.Forte@Sun.COM 		ASSERT(tp->tp_link.q_forw != NULL &&
3577836SJohn.Forte@Sun.COM 		    tp->tp_link.q_back != NULL);
3587836SJohn.Forte@Sun.COM 		nst_remque(&tp->tp_link);
3597836SJohn.Forte@Sun.COM 	}
3607836SJohn.Forte@Sun.COM 
3617836SJohn.Forte@Sun.COM 	set->set_nthread--;
3627836SJohn.Forte@Sun.COM 	tp->tp_flag &= ~NST_TF_KILL;
3637836SJohn.Forte@Sun.COM 
3647836SJohn.Forte@Sun.COM 	/* wake the context that is running nst_destroy() or nst_del_thread() */
3657836SJohn.Forte@Sun.COM 	cv_broadcast(&set->set_kill_cv);
3667836SJohn.Forte@Sun.COM 
3677836SJohn.Forte@Sun.COM 	mutex_exit(&set->set_lock);
3687836SJohn.Forte@Sun.COM 
3697836SJohn.Forte@Sun.COM 	/* suicide */
3707836SJohn.Forte@Sun.COM }
3717836SJohn.Forte@Sun.COM 
3727836SJohn.Forte@Sun.COM 
3737836SJohn.Forte@Sun.COM /*
3747836SJohn.Forte@Sun.COM  * nst_thread_destroy
3757836SJohn.Forte@Sun.COM  *
3767836SJohn.Forte@Sun.COM  * Free up the kernel level resources.  The thread must already be
3777836SJohn.Forte@Sun.COM  * un-chained from the set, and the caller must not be the thread
3787836SJohn.Forte@Sun.COM  * itself.
3797836SJohn.Forte@Sun.COM  */
3807836SJohn.Forte@Sun.COM static void
nst_thread_destroy(nsthread_t * tp)3817836SJohn.Forte@Sun.COM nst_thread_destroy(nsthread_t *tp)
3827836SJohn.Forte@Sun.COM {
3837836SJohn.Forte@Sun.COM 	if (!tp)
3847836SJohn.Forte@Sun.COM 		return;
3857836SJohn.Forte@Sun.COM 
3867836SJohn.Forte@Sun.COM 	ASSERT(tp->tp_chain == NULL);
3877836SJohn.Forte@Sun.COM 
3887836SJohn.Forte@Sun.COM 	tp->tp_set = NULL;
3897836SJohn.Forte@Sun.COM 
3907836SJohn.Forte@Sun.COM 	if (tp->tp_flag & NST_TF_INUSE) {
391*9093SRamana.Srikanth@Sun.COM 		cmn_err(CE_WARN, "!nst_thread_destroy(%p): still in use!",
3927836SJohn.Forte@Sun.COM 		    (void *)tp);
3937836SJohn.Forte@Sun.COM 		/* leak the thread */
3947836SJohn.Forte@Sun.COM 		return;
3957836SJohn.Forte@Sun.COM 	}
3967836SJohn.Forte@Sun.COM 
3977836SJohn.Forte@Sun.COM 	cv_destroy(&tp->tp_cv);
3987836SJohn.Forte@Sun.COM 	kmem_free(tp, sizeof (*tp));
3997836SJohn.Forte@Sun.COM }
4007836SJohn.Forte@Sun.COM 
4017836SJohn.Forte@Sun.COM 
4027836SJohn.Forte@Sun.COM /*
4037836SJohn.Forte@Sun.COM  * nst_thread_create
4047836SJohn.Forte@Sun.COM  *
4057836SJohn.Forte@Sun.COM  * Create and return a new thread from a threadset.
4067836SJohn.Forte@Sun.COM  */
4077836SJohn.Forte@Sun.COM static nsthread_t *
nst_thread_create(nstset_t * set)4087836SJohn.Forte@Sun.COM nst_thread_create(nstset_t *set)
4097836SJohn.Forte@Sun.COM {
4107836SJohn.Forte@Sun.COM 	nsthread_t *tp, **tpp;
4117836SJohn.Forte@Sun.COM 	int rc;
4127836SJohn.Forte@Sun.COM 
4137836SJohn.Forte@Sun.COM 	/* try and reuse a thread first */
4147836SJohn.Forte@Sun.COM 
4157836SJohn.Forte@Sun.COM 	if (set->set_reuse.q_forw != &set->set_reuse) {
4167836SJohn.Forte@Sun.COM 		mutex_enter(&set->set_lock);
4177836SJohn.Forte@Sun.COM 
4187836SJohn.Forte@Sun.COM 		tp = (nsthread_t *)set->set_reuse.q_forw;
4197836SJohn.Forte@Sun.COM 		if (tp != (nsthread_t *)&set->set_reuse)
4207836SJohn.Forte@Sun.COM 			nst_remque(&tp->tp_link);
4217836SJohn.Forte@Sun.COM 		else
4227836SJohn.Forte@Sun.COM 			tp = NULL;
4237836SJohn.Forte@Sun.COM 
4247836SJohn.Forte@Sun.COM 		mutex_exit(&set->set_lock);
4257836SJohn.Forte@Sun.COM 
4267836SJohn.Forte@Sun.COM 		if (tp) {
427*9093SRamana.Srikanth@Sun.COM 			DTRACE_PROBE2(nst_thread_create_end, nstset_t *, set,
428*9093SRamana.Srikanth@Sun.COM 			    nsthread_t *, tp);
4297836SJohn.Forte@Sun.COM 			return (tp);
4307836SJohn.Forte@Sun.COM 		}
4317836SJohn.Forte@Sun.COM 	}
4327836SJohn.Forte@Sun.COM 
4337836SJohn.Forte@Sun.COM 	/* create a thread using nskernd */
4347836SJohn.Forte@Sun.COM 
4357836SJohn.Forte@Sun.COM 	tp = nst_kmem_zalloc(sizeof (*tp), 2);
4367836SJohn.Forte@Sun.COM 	if (!tp) {
437*9093SRamana.Srikanth@Sun.COM 		DTRACE_PROBE1(nst_thread_create_err_mem, nstset_t *, set);
4387836SJohn.Forte@Sun.COM 		return (NULL);
4397836SJohn.Forte@Sun.COM 	}
4407836SJohn.Forte@Sun.COM 
4417836SJohn.Forte@Sun.COM 	cv_init(&tp->tp_cv, NULL, CV_DRIVER, NULL);
4427836SJohn.Forte@Sun.COM 	tp->tp_flag = NST_TF_PENDING;
4437836SJohn.Forte@Sun.COM 	tp->tp_set = set;
4447836SJohn.Forte@Sun.COM 
4457836SJohn.Forte@Sun.COM 	mutex_enter(&set->set_lock);
4467836SJohn.Forte@Sun.COM 
4477836SJohn.Forte@Sun.COM 	if (set->set_flag & NST_SF_KILL) {
4487836SJohn.Forte@Sun.COM 		mutex_exit(&set->set_lock);
4497836SJohn.Forte@Sun.COM 		nst_thread_destroy(tp);
4507836SJohn.Forte@Sun.COM #ifdef DEBUG
451*9093SRamana.Srikanth@Sun.COM 		cmn_err(CE_WARN, "!nst_thread_create: called during destroy");
4527836SJohn.Forte@Sun.COM #endif
453*9093SRamana.Srikanth@Sun.COM 		DTRACE_PROBE2(nst_thread_create_err_kill, nstset_t *, set,
454*9093SRamana.Srikanth@Sun.COM 		    nsthread_t *, tp);
4557836SJohn.Forte@Sun.COM 		return (NULL);
4567836SJohn.Forte@Sun.COM 	}
4577836SJohn.Forte@Sun.COM 
4587836SJohn.Forte@Sun.COM 	set->set_pending++;
4597836SJohn.Forte@Sun.COM 
4607836SJohn.Forte@Sun.COM 	mutex_exit(&set->set_lock);
4617836SJohn.Forte@Sun.COM 
4627836SJohn.Forte@Sun.COM 	mutex_enter(&nst_global_lock);
4637836SJohn.Forte@Sun.COM 
4647836SJohn.Forte@Sun.COM 	tp->tp_chain = nst_pending;
4657836SJohn.Forte@Sun.COM 	nst_pending = tp;
4667836SJohn.Forte@Sun.COM 
4677836SJohn.Forte@Sun.COM 	mutex_exit(&nst_global_lock);
4687836SJohn.Forte@Sun.COM 
469*9093SRamana.Srikanth@Sun.COM 	DTRACE_PROBE2(nst_dbg_thr_create_proc_start, nstset_t *, set,
470*9093SRamana.Srikanth@Sun.COM 	    nsthread_t *, tp);
4717836SJohn.Forte@Sun.COM 
4727836SJohn.Forte@Sun.COM 	rc = nsc_create_process(nst_thread_run, tp, 0);
4737836SJohn.Forte@Sun.COM 
474*9093SRamana.Srikanth@Sun.COM 	DTRACE_PROBE2(nst_dbg_thr_create_proc_end, nstset_t *, set,
475*9093SRamana.Srikanth@Sun.COM 	    nsthread_t *, tp);
4767836SJohn.Forte@Sun.COM 
4777836SJohn.Forte@Sun.COM 	if (!rc) {
4787836SJohn.Forte@Sun.COM 		/*
4797836SJohn.Forte@Sun.COM 		 * wait for child to start and check in.
4807836SJohn.Forte@Sun.COM 		 */
4817836SJohn.Forte@Sun.COM 
4827836SJohn.Forte@Sun.COM 		mutex_enter(&set->set_lock);
4837836SJohn.Forte@Sun.COM 
4847836SJohn.Forte@Sun.COM 		while (tp->tp_flag & NST_TF_PENDING)
4857836SJohn.Forte@Sun.COM 			cv_wait(&tp->tp_cv, &set->set_lock);
4867836SJohn.Forte@Sun.COM 
4877836SJohn.Forte@Sun.COM 		mutex_exit(&set->set_lock);
4887836SJohn.Forte@Sun.COM 	}
4897836SJohn.Forte@Sun.COM 
4907836SJohn.Forte@Sun.COM 	/*
4917836SJohn.Forte@Sun.COM 	 * remove from pending chain.
4927836SJohn.Forte@Sun.COM 	 */
4937836SJohn.Forte@Sun.COM 
4947836SJohn.Forte@Sun.COM 	mutex_enter(&nst_global_lock);
4957836SJohn.Forte@Sun.COM 
4967836SJohn.Forte@Sun.COM 	for (tpp = &nst_pending; (*tpp); tpp = &((*tpp)->tp_chain)) {
4977836SJohn.Forte@Sun.COM 		if (*tpp == tp) {
4987836SJohn.Forte@Sun.COM 			*tpp = tp->tp_chain;
4997836SJohn.Forte@Sun.COM 			tp->tp_chain = NULL;
5007836SJohn.Forte@Sun.COM 			break;
5017836SJohn.Forte@Sun.COM 		}
5027836SJohn.Forte@Sun.COM 	}
5037836SJohn.Forte@Sun.COM 
5047836SJohn.Forte@Sun.COM 	mutex_exit(&nst_global_lock);
5057836SJohn.Forte@Sun.COM 
5067836SJohn.Forte@Sun.COM 	/*
5077836SJohn.Forte@Sun.COM 	 * Check for errors and return if required.
5087836SJohn.Forte@Sun.COM 	 */
5097836SJohn.Forte@Sun.COM 
5107836SJohn.Forte@Sun.COM 	mutex_enter(&set->set_lock);
5117836SJohn.Forte@Sun.COM 
5127836SJohn.Forte@Sun.COM 	set->set_pending--;
5137836SJohn.Forte@Sun.COM 
5147836SJohn.Forte@Sun.COM 	if (rc ||
5157836SJohn.Forte@Sun.COM 	    (set->set_flag & NST_SF_KILL) ||
5167836SJohn.Forte@Sun.COM 	    (set->set_nthread + 1) > USHRT_MAX) {
5177836SJohn.Forte@Sun.COM 		if (rc == 0) {
5187836SJohn.Forte@Sun.COM 			/*
5197836SJohn.Forte@Sun.COM 			 * Thread is alive, and needs to be woken and killed.
5207836SJohn.Forte@Sun.COM 			 */
5217836SJohn.Forte@Sun.COM 			tp->tp_flag |= NST_TF_KILL;
5227836SJohn.Forte@Sun.COM 			cv_broadcast(&tp->tp_cv);
5237836SJohn.Forte@Sun.COM 
5247836SJohn.Forte@Sun.COM 			while (tp->tp_flag & NST_TF_KILL)
5257836SJohn.Forte@Sun.COM 				cv_wait(&set->set_kill_cv, &set->set_lock);
5267836SJohn.Forte@Sun.COM 		}
5277836SJohn.Forte@Sun.COM 		mutex_exit(&set->set_lock);
5287836SJohn.Forte@Sun.COM 
5297836SJohn.Forte@Sun.COM 		nst_thread_destroy(tp);
5307836SJohn.Forte@Sun.COM #ifdef DEBUG
5317836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN,
532*9093SRamana.Srikanth@Sun.COM 		    "!nst_thread_create: error (rc %d, set_flag %x, "
533*9093SRamana.Srikanth@Sun.COM 		    "set_nthread %d)", rc, set->set_flag, set->set_nthread);
5347836SJohn.Forte@Sun.COM #endif
535*9093SRamana.Srikanth@Sun.COM 		DTRACE_PROBE2(nst_thread_create_err_proc, nstset_t *, set,
536*9093SRamana.Srikanth@Sun.COM 		    nsthread_t *, tp);
5377836SJohn.Forte@Sun.COM 
5387836SJohn.Forte@Sun.COM 		return (NULL);
5397836SJohn.Forte@Sun.COM 	}
5407836SJohn.Forte@Sun.COM 
5417836SJohn.Forte@Sun.COM 	/*
5427836SJohn.Forte@Sun.COM 	 * Move into set proper.
5437836SJohn.Forte@Sun.COM 	 */
5447836SJohn.Forte@Sun.COM 
5457836SJohn.Forte@Sun.COM 	tp->tp_chain = set->set_chain;
5467836SJohn.Forte@Sun.COM 	set->set_chain = tp;
5477836SJohn.Forte@Sun.COM 	set->set_nthread++;
5487836SJohn.Forte@Sun.COM 
5497836SJohn.Forte@Sun.COM 	mutex_exit(&set->set_lock);
5507836SJohn.Forte@Sun.COM 
5517836SJohn.Forte@Sun.COM 	return (tp);
5527836SJohn.Forte@Sun.COM }
5537836SJohn.Forte@Sun.COM 
5547836SJohn.Forte@Sun.COM 
5557836SJohn.Forte@Sun.COM /*
5567836SJohn.Forte@Sun.COM  * nst_create
5577836SJohn.Forte@Sun.COM  *
5587836SJohn.Forte@Sun.COM  * Start a new thread from a thread set, returning the
5597836SJohn.Forte@Sun.COM  * address of the thread, or NULL on failure.
5607836SJohn.Forte@Sun.COM  *
5617836SJohn.Forte@Sun.COM  * All threads are created detached.
5627836SJohn.Forte@Sun.COM  *
5637836SJohn.Forte@Sun.COM  * Valid flag values:
5647836SJohn.Forte@Sun.COM  *
5657836SJohn.Forte@Sun.COM  *      NST_CREATE      - create a new thread rather than using one
5667836SJohn.Forte@Sun.COM  *                        from the threadset.  Once the thread
5677836SJohn.Forte@Sun.COM  *                        completes it will not be added to the active
5687836SJohn.Forte@Sun.COM  *                        portion of the threadset, but will be cached
5697836SJohn.Forte@Sun.COM  *                        on the reuse chain, and so is available for
5707836SJohn.Forte@Sun.COM  *                        subsequent NST_CREATE or nst_add_thread()
5717836SJohn.Forte@Sun.COM  *			  operations.
5727836SJohn.Forte@Sun.COM  *
5737836SJohn.Forte@Sun.COM  *	NST_SLEEP	- wait for a thread to be available instead of
5747836SJohn.Forte@Sun.COM  *			  returning NULL.  Has no meaning with NST_CREATE.
5757836SJohn.Forte@Sun.COM  *
5767836SJohn.Forte@Sun.COM  * Returns a pointer to the new thread, or NULL.
5777836SJohn.Forte@Sun.COM  */
5787836SJohn.Forte@Sun.COM nsthread_t *
nst_create(nstset_t * set,void (* func)(),blind_t arg,int flags)5797836SJohn.Forte@Sun.COM nst_create(nstset_t *set, void (*func)(), blind_t arg, int flags)
5807836SJohn.Forte@Sun.COM {
5817836SJohn.Forte@Sun.COM 	nsthread_t *tp = NULL;
5827836SJohn.Forte@Sun.COM 
5837836SJohn.Forte@Sun.COM 	if (!set)
5847836SJohn.Forte@Sun.COM 		return (NULL);
5857836SJohn.Forte@Sun.COM 
5867836SJohn.Forte@Sun.COM 	if (set->set_flag & NST_SF_KILL) {
587*9093SRamana.Srikanth@Sun.COM 		DTRACE_PROBE1(nst_create_err_kill, nstset_t *, set);
5887836SJohn.Forte@Sun.COM 		return (NULL);
5897836SJohn.Forte@Sun.COM 	}
5907836SJohn.Forte@Sun.COM 
5917836SJohn.Forte@Sun.COM 	if (flags & NST_CREATE) {
5927836SJohn.Forte@Sun.COM 		/* get new thread */
5937836SJohn.Forte@Sun.COM 
5947836SJohn.Forte@Sun.COM 		if ((tp = nst_thread_create(set)) == NULL)
5957836SJohn.Forte@Sun.COM 			return (NULL);
5967836SJohn.Forte@Sun.COM 
5977836SJohn.Forte@Sun.COM 		/* initialise the thread */
5987836SJohn.Forte@Sun.COM 
5997836SJohn.Forte@Sun.COM 		mutex_enter(&set->set_lock);
6007836SJohn.Forte@Sun.COM 		nst_thread_init(tp);
6017836SJohn.Forte@Sun.COM 		tp->tp_flag |= NST_TF_DESTROY;
6027836SJohn.Forte@Sun.COM 		set->set_nlive++;
6037836SJohn.Forte@Sun.COM 		mutex_exit(&set->set_lock);
6047836SJohn.Forte@Sun.COM 	} else {
6057836SJohn.Forte@Sun.COM 		if (!(tp = nst_thread_alloc(set, (flags & NST_SLEEP))))
6067836SJohn.Forte@Sun.COM 			return (NULL);
6077836SJohn.Forte@Sun.COM 	}
6087836SJohn.Forte@Sun.COM 
6097836SJohn.Forte@Sun.COM 	/* set thread running */
6107836SJohn.Forte@Sun.COM 
6117836SJohn.Forte@Sun.COM 	tp->tp_func = func;
6127836SJohn.Forte@Sun.COM 	tp->tp_arg = arg;
6137836SJohn.Forte@Sun.COM 
6147836SJohn.Forte@Sun.COM 	mutex_enter(&set->set_lock);
6157836SJohn.Forte@Sun.COM 	cv_broadcast(&tp->tp_cv);
6167836SJohn.Forte@Sun.COM 	mutex_exit(&set->set_lock);
6177836SJohn.Forte@Sun.COM 
6187836SJohn.Forte@Sun.COM 	return (tp);
6197836SJohn.Forte@Sun.COM }
6207836SJohn.Forte@Sun.COM 
6217836SJohn.Forte@Sun.COM 
6227836SJohn.Forte@Sun.COM /*
6237836SJohn.Forte@Sun.COM  * nst_destroy
6247836SJohn.Forte@Sun.COM  *
6257836SJohn.Forte@Sun.COM  * Destroy a thread set created by nst_init(). It is the
6267836SJohn.Forte@Sun.COM  * caller's responsibility to ensure that all prior thread
6277836SJohn.Forte@Sun.COM  * calls have completed prior to this call and that the
6287836SJohn.Forte@Sun.COM  * caller is not executing from within thread context.
6297836SJohn.Forte@Sun.COM  */
6307836SJohn.Forte@Sun.COM void
nst_destroy(nstset_t * set)6317836SJohn.Forte@Sun.COM nst_destroy(nstset_t *set)
6327836SJohn.Forte@Sun.COM {
6337836SJohn.Forte@Sun.COM 	nsthread_t *tp, *ntp;
6347836SJohn.Forte@Sun.COM 	nstset_t *sp, **spp;
6357836SJohn.Forte@Sun.COM 
6367836SJohn.Forte@Sun.COM 	if (!set)
6377836SJohn.Forte@Sun.COM 		return;
6387836SJohn.Forte@Sun.COM 
6397836SJohn.Forte@Sun.COM 	mutex_enter(&nst_global_lock);
6407836SJohn.Forte@Sun.COM 
6417836SJohn.Forte@Sun.COM 	for (sp = nst_sets; sp; sp = sp->set_next) {
6427836SJohn.Forte@Sun.COM 		if (sp == set) {
6437836SJohn.Forte@Sun.COM 			break;
6447836SJohn.Forte@Sun.COM 		}
6457836SJohn.Forte@Sun.COM 	}
6467836SJohn.Forte@Sun.COM 
6477836SJohn.Forte@Sun.COM 	if (!sp) {
6487836SJohn.Forte@Sun.COM 		mutex_exit(&nst_global_lock);
6497836SJohn.Forte@Sun.COM #ifdef DEBUG
650*9093SRamana.Srikanth@Sun.COM 		cmn_err(CE_WARN, "!nst_destroy(%p): no set?", (void *)set);
6517836SJohn.Forte@Sun.COM #endif
652*9093SRamana.Srikanth@Sun.COM 		DTRACE_PROBE1(nst_destroy_err_noset, nstset_t *, set);
6537836SJohn.Forte@Sun.COM 		return;
6547836SJohn.Forte@Sun.COM 	}
6557836SJohn.Forte@Sun.COM 
6567836SJohn.Forte@Sun.COM 	mutex_enter(&set->set_lock);
6577836SJohn.Forte@Sun.COM 
6587836SJohn.Forte@Sun.COM 	mutex_exit(&nst_global_lock);
6597836SJohn.Forte@Sun.COM 
6607836SJohn.Forte@Sun.COM 	if (set->set_flag & NST_SF_KILL) {
6617836SJohn.Forte@Sun.COM 		/*
6627836SJohn.Forte@Sun.COM 		 * Wait for a pending destroy to complete
6637836SJohn.Forte@Sun.COM 		 */
6647836SJohn.Forte@Sun.COM 
6657836SJohn.Forte@Sun.COM #ifdef DEBUG
6667836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN,
667*9093SRamana.Srikanth@Sun.COM 		    "!nst_destroy(%p): duplicate destroy of set", (void *)set);
6687836SJohn.Forte@Sun.COM #endif
6697836SJohn.Forte@Sun.COM 
6707836SJohn.Forte@Sun.COM 		set->set_destroy_cnt++;
6717836SJohn.Forte@Sun.COM 		(void) cv_wait_sig(&set->set_destroy_cv, &set->set_lock);
6727836SJohn.Forte@Sun.COM 		set->set_destroy_cnt--;
6737836SJohn.Forte@Sun.COM 
6747836SJohn.Forte@Sun.COM 		mutex_exit(&set->set_lock);
6757836SJohn.Forte@Sun.COM 
676*9093SRamana.Srikanth@Sun.COM 		DTRACE_PROBE1(nst_destroy_end, nstset_t *, set);
6777836SJohn.Forte@Sun.COM 
6787836SJohn.Forte@Sun.COM 		return;
6797836SJohn.Forte@Sun.COM 	}
6807836SJohn.Forte@Sun.COM 
6817836SJohn.Forte@Sun.COM 	set->set_flag |= NST_SF_KILL;
6827836SJohn.Forte@Sun.COM 
6837836SJohn.Forte@Sun.COM 	/* Wake all threads in nst_create(NST_SLEEP) */
6847836SJohn.Forte@Sun.COM 	cv_broadcast(&set->set_res_cv);
6857836SJohn.Forte@Sun.COM 
6867836SJohn.Forte@Sun.COM 	/*
6877836SJohn.Forte@Sun.COM 	 * Wake all the threads chained in the set.
6887836SJohn.Forte@Sun.COM 	 */
6897836SJohn.Forte@Sun.COM 
6907836SJohn.Forte@Sun.COM 	for (tp = set->set_chain; tp; tp = tp->tp_chain)
6917836SJohn.Forte@Sun.COM 		cv_broadcast(&tp->tp_cv);
6927836SJohn.Forte@Sun.COM 
6937836SJohn.Forte@Sun.COM 	/* Wait for the threads to exit */
6947836SJohn.Forte@Sun.COM 
6957836SJohn.Forte@Sun.COM 	while ((set->set_free.q_forw != &set->set_free) ||
6967836SJohn.Forte@Sun.COM 	    (set->set_reuse.q_forw != &set->set_reuse))
6977836SJohn.Forte@Sun.COM 		cv_wait(&set->set_kill_cv, &set->set_lock);
6987836SJohn.Forte@Sun.COM 
6997836SJohn.Forte@Sun.COM 	/* Unchain and destroy all the threads in the set */
7007836SJohn.Forte@Sun.COM 
7017836SJohn.Forte@Sun.COM 	tp = set->set_chain;
7027836SJohn.Forte@Sun.COM 	set->set_chain = 0;
7037836SJohn.Forte@Sun.COM 
7047836SJohn.Forte@Sun.COM 	while (tp) {
7057836SJohn.Forte@Sun.COM 		ntp = tp->tp_chain;
7067836SJohn.Forte@Sun.COM 		tp->tp_chain = 0;
7077836SJohn.Forte@Sun.COM 
7087836SJohn.Forte@Sun.COM 		nst_thread_destroy(tp);
7097836SJohn.Forte@Sun.COM 
7107836SJohn.Forte@Sun.COM 		tp = ntp;
7117836SJohn.Forte@Sun.COM 	}
7127836SJohn.Forte@Sun.COM 
7137836SJohn.Forte@Sun.COM 	mutex_exit(&set->set_lock);
7147836SJohn.Forte@Sun.COM 
7157836SJohn.Forte@Sun.COM 	mutex_enter(&nst_global_lock);
7167836SJohn.Forte@Sun.COM 
7177836SJohn.Forte@Sun.COM 	/* remove the set from the chain */
7187836SJohn.Forte@Sun.COM 
7197836SJohn.Forte@Sun.COM 	for (spp = &nst_sets; *spp; spp = &((*spp)->set_next)) {
7207836SJohn.Forte@Sun.COM 		if (*spp == set) {
7217836SJohn.Forte@Sun.COM 			*spp = set->set_next;
7227836SJohn.Forte@Sun.COM 			set->set_next = NULL;
7237836SJohn.Forte@Sun.COM 			break;
7247836SJohn.Forte@Sun.COM 		}
7257836SJohn.Forte@Sun.COM 	}
7267836SJohn.Forte@Sun.COM 
7277836SJohn.Forte@Sun.COM 	mutex_exit(&nst_global_lock);
7287836SJohn.Forte@Sun.COM 
7297836SJohn.Forte@Sun.COM 	mutex_enter(&set->set_lock);
7307836SJohn.Forte@Sun.COM 
7317836SJohn.Forte@Sun.COM #ifdef DEBUG
7327836SJohn.Forte@Sun.COM 	if (set->set_nthread != 0) {
733*9093SRamana.Srikanth@Sun.COM 		cmn_err(CE_WARN, "!nst_destroy(%p): nthread != 0 (%d)",
7347836SJohn.Forte@Sun.COM 		    (void *)set, set->set_nthread);
7357836SJohn.Forte@Sun.COM 	}
7367836SJohn.Forte@Sun.COM #endif
7377836SJohn.Forte@Sun.COM 
7387836SJohn.Forte@Sun.COM 	/* Allow any waiters (above) to continue */
7397836SJohn.Forte@Sun.COM 
7407836SJohn.Forte@Sun.COM 	cv_broadcast(&set->set_destroy_cv);
7417836SJohn.Forte@Sun.COM 
7427836SJohn.Forte@Sun.COM 	while (set->set_destroy_cnt > 0 || set->set_pending > 0 ||
7437836SJohn.Forte@Sun.COM 	    set->set_res_cnt > 0) {
7447836SJohn.Forte@Sun.COM 		mutex_exit(&set->set_lock);
7457836SJohn.Forte@Sun.COM 		delay(drv_usectohz((clock_t)NST_KILL_TIMEOUT));
7467836SJohn.Forte@Sun.COM 		mutex_enter(&set->set_lock);
7477836SJohn.Forte@Sun.COM 	}
7487836SJohn.Forte@Sun.COM 
7497836SJohn.Forte@Sun.COM 	mutex_exit(&set->set_lock);
7507836SJohn.Forte@Sun.COM 
7517836SJohn.Forte@Sun.COM 	if (set->set_nthread != 0) {
7527836SJohn.Forte@Sun.COM 		/* leak the set control structure */
7537836SJohn.Forte@Sun.COM 
754*9093SRamana.Srikanth@Sun.COM 		DTRACE_PROBE1(nst_destroy_end, nstset_t *, set);
7557836SJohn.Forte@Sun.COM 
7567836SJohn.Forte@Sun.COM 		return;
7577836SJohn.Forte@Sun.COM 	}
7587836SJohn.Forte@Sun.COM 
7597836SJohn.Forte@Sun.COM 	cv_destroy(&set->set_res_cv);
7607836SJohn.Forte@Sun.COM 	cv_destroy(&set->set_kill_cv);
7617836SJohn.Forte@Sun.COM 	cv_destroy(&set->set_destroy_cv);
7627836SJohn.Forte@Sun.COM 	mutex_destroy(&set->set_lock);
7637836SJohn.Forte@Sun.COM 	kmem_free(set, sizeof (*set));
7647836SJohn.Forte@Sun.COM 
7657836SJohn.Forte@Sun.COM }
7667836SJohn.Forte@Sun.COM 
7677836SJohn.Forte@Sun.COM 
7687836SJohn.Forte@Sun.COM /*
7697836SJohn.Forte@Sun.COM  * nst_add_thread
7707836SJohn.Forte@Sun.COM  *
7717836SJohn.Forte@Sun.COM  * Add more threads into an existing thread set.
7727836SJohn.Forte@Sun.COM  * Returns the number successfully added.
7737836SJohn.Forte@Sun.COM  */
7747836SJohn.Forte@Sun.COM int
nst_add_thread(nstset_t * set,int nthread)7757836SJohn.Forte@Sun.COM nst_add_thread(nstset_t *set, int nthread)
7767836SJohn.Forte@Sun.COM {
7777836SJohn.Forte@Sun.COM 	nsthread_t *tp;
7787836SJohn.Forte@Sun.COM 	int i;
7797836SJohn.Forte@Sun.COM 
7807836SJohn.Forte@Sun.COM 	if (!set || nthread < 1) {
7817836SJohn.Forte@Sun.COM #ifdef DEBUG
7827836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN,
783*9093SRamana.Srikanth@Sun.COM 		    "!nst_add_thread(%p, %d) - bad args", (void *)set, nthread);
7847836SJohn.Forte@Sun.COM #endif
7857836SJohn.Forte@Sun.COM 		return (0);
7867836SJohn.Forte@Sun.COM 	}
7877836SJohn.Forte@Sun.COM 
7887836SJohn.Forte@Sun.COM 	for (i = 0; i < nthread; i++) {
7897836SJohn.Forte@Sun.COM 		/* get new thread */
7907836SJohn.Forte@Sun.COM 
7917836SJohn.Forte@Sun.COM 		if ((tp = nst_thread_create(set)) == NULL)
7927836SJohn.Forte@Sun.COM 			break;
7937836SJohn.Forte@Sun.COM 
7947836SJohn.Forte@Sun.COM 		/* add to free list */
7957836SJohn.Forte@Sun.COM 
7967836SJohn.Forte@Sun.COM 		mutex_enter(&set->set_lock);
7977836SJohn.Forte@Sun.COM 		nst_thread_free(tp);
7987836SJohn.Forte@Sun.COM 		mutex_exit(&set->set_lock);
7997836SJohn.Forte@Sun.COM 	}
8007836SJohn.Forte@Sun.COM 
8017836SJohn.Forte@Sun.COM 	return (i);
8027836SJohn.Forte@Sun.COM }
8037836SJohn.Forte@Sun.COM 
8047836SJohn.Forte@Sun.COM 
8057836SJohn.Forte@Sun.COM /*
8067836SJohn.Forte@Sun.COM  * nst_del_thread
8077836SJohn.Forte@Sun.COM  *
8087836SJohn.Forte@Sun.COM  * Removes threads from an existing thread set.
8097836SJohn.Forte@Sun.COM  * Returns the number successfully removed.
8107836SJohn.Forte@Sun.COM  */
8117836SJohn.Forte@Sun.COM int
nst_del_thread(nstset_t * set,int nthread)8127836SJohn.Forte@Sun.COM nst_del_thread(nstset_t *set, int nthread)
8137836SJohn.Forte@Sun.COM {
8147836SJohn.Forte@Sun.COM 	nsthread_t **tpp, *tp;
8157836SJohn.Forte@Sun.COM 	int i;
8167836SJohn.Forte@Sun.COM 
8177836SJohn.Forte@Sun.COM 	if (!set || nthread < 1) {
8187836SJohn.Forte@Sun.COM #ifdef DEBUG
8197836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN,
820*9093SRamana.Srikanth@Sun.COM 		    "!nst_del_thread(%p, %d) - bad args", (void *)set, nthread);
8217836SJohn.Forte@Sun.COM #endif
8227836SJohn.Forte@Sun.COM 		return (0);
8237836SJohn.Forte@Sun.COM 	}
8247836SJohn.Forte@Sun.COM 
8257836SJohn.Forte@Sun.COM 	for (i = 0; i < nthread; i++) {
8267836SJohn.Forte@Sun.COM 		/* get thread */
8277836SJohn.Forte@Sun.COM 
8287836SJohn.Forte@Sun.COM 		if (!(tp = nst_thread_alloc(set, FALSE)))
8297836SJohn.Forte@Sun.COM 			break;
8307836SJohn.Forte@Sun.COM 
8317836SJohn.Forte@Sun.COM 		mutex_enter(&set->set_lock);
8327836SJohn.Forte@Sun.COM 
8337836SJohn.Forte@Sun.COM 		/* unlink from the set */
8347836SJohn.Forte@Sun.COM 
8357836SJohn.Forte@Sun.COM 		for (tpp = &set->set_chain; *tpp; tpp = &(*tpp)->tp_chain) {
8367836SJohn.Forte@Sun.COM 			if (*tpp == tp) {
8377836SJohn.Forte@Sun.COM 				*tpp = tp->tp_chain;
8387836SJohn.Forte@Sun.COM 				tp->tp_chain = NULL;
8397836SJohn.Forte@Sun.COM 				break;
8407836SJohn.Forte@Sun.COM 			}
8417836SJohn.Forte@Sun.COM 		}
8427836SJohn.Forte@Sun.COM 
8437836SJohn.Forte@Sun.COM 		/* kill the thread */
8447836SJohn.Forte@Sun.COM 
8457836SJohn.Forte@Sun.COM 		tp->tp_flag |= NST_TF_KILL;
8467836SJohn.Forte@Sun.COM 		tp->tp_flag &= ~NST_TF_INUSE;
8477836SJohn.Forte@Sun.COM 		cv_broadcast(&tp->tp_cv);
8487836SJohn.Forte@Sun.COM 
8497836SJohn.Forte@Sun.COM 		/* wait for thread to exit */
8507836SJohn.Forte@Sun.COM 
8517836SJohn.Forte@Sun.COM 		while (tp->tp_flag & NST_TF_KILL)
8527836SJohn.Forte@Sun.COM 			cv_wait(&set->set_kill_cv, &set->set_lock);
8537836SJohn.Forte@Sun.COM 
8547836SJohn.Forte@Sun.COM 		set->set_nlive--;
8557836SJohn.Forte@Sun.COM 		mutex_exit(&set->set_lock);
8567836SJohn.Forte@Sun.COM 
8577836SJohn.Forte@Sun.COM 		/* free kernel resources */
8587836SJohn.Forte@Sun.COM 
8597836SJohn.Forte@Sun.COM 		nst_thread_destroy(tp);
8607836SJohn.Forte@Sun.COM 	}
8617836SJohn.Forte@Sun.COM 
8627836SJohn.Forte@Sun.COM 	return (i);
8637836SJohn.Forte@Sun.COM }
8647836SJohn.Forte@Sun.COM 
8657836SJohn.Forte@Sun.COM 
8667836SJohn.Forte@Sun.COM /*
8677836SJohn.Forte@Sun.COM  * nst_init
8687836SJohn.Forte@Sun.COM  *
8697836SJohn.Forte@Sun.COM  * Initialise a new nsthread set, returning its address or
8707836SJohn.Forte@Sun.COM  * NULL in the event of failure. The set should be destroyed
8717836SJohn.Forte@Sun.COM  * by calling nst_destroy().
8727836SJohn.Forte@Sun.COM  */
8737836SJohn.Forte@Sun.COM nstset_t *
nst_init(char * name,int nthread)8747836SJohn.Forte@Sun.COM nst_init(char *name, int nthread)
8757836SJohn.Forte@Sun.COM {
8767836SJohn.Forte@Sun.COM 	nstset_t *set, *sp;
8777836SJohn.Forte@Sun.COM 	int len, i;
8787836SJohn.Forte@Sun.COM 
8797836SJohn.Forte@Sun.COM 	if (nthread < 1) {
8807836SJohn.Forte@Sun.COM #ifdef DEBUG
881*9093SRamana.Srikanth@Sun.COM 		cmn_err(CE_WARN, "!nst_init: invalid arg");
8827836SJohn.Forte@Sun.COM #endif
8837836SJohn.Forte@Sun.COM 		return (NULL);
8847836SJohn.Forte@Sun.COM 	}
8857836SJohn.Forte@Sun.COM 
8867836SJohn.Forte@Sun.COM 	if (nthread > USHRT_MAX) {
8877836SJohn.Forte@Sun.COM #ifdef DEBUG
888*9093SRamana.Srikanth@Sun.COM 		cmn_err(CE_WARN, "!nst_init: arg limit exceeded");
8897836SJohn.Forte@Sun.COM #endif
8907836SJohn.Forte@Sun.COM 		return (NULL);
8917836SJohn.Forte@Sun.COM 	}
8927836SJohn.Forte@Sun.COM 
8937836SJohn.Forte@Sun.COM 	if (!(set = nst_kmem_zalloc(sizeof (*set), 2)))
8947836SJohn.Forte@Sun.COM 		return (NULL);
8957836SJohn.Forte@Sun.COM 
8967836SJohn.Forte@Sun.COM 	len = strlen(name);
8977836SJohn.Forte@Sun.COM 	if (len >= sizeof (set->set_name))
8987836SJohn.Forte@Sun.COM 		len = sizeof (set->set_name) - 1;
8997836SJohn.Forte@Sun.COM 
9007836SJohn.Forte@Sun.COM 	bcopy(name, set->set_name, len);
9017836SJohn.Forte@Sun.COM 
9027836SJohn.Forte@Sun.COM 	mutex_init(&set->set_lock, NULL, MUTEX_DRIVER, NULL);
9037836SJohn.Forte@Sun.COM 	cv_init(&set->set_destroy_cv, NULL, CV_DRIVER, NULL);
9047836SJohn.Forte@Sun.COM 	cv_init(&set->set_kill_cv, NULL, CV_DRIVER, NULL);
9057836SJohn.Forte@Sun.COM 	cv_init(&set->set_res_cv, NULL, CV_DRIVER, NULL);
9067836SJohn.Forte@Sun.COM 
9077836SJohn.Forte@Sun.COM 	set->set_reuse.q_forw = set->set_reuse.q_back = &set->set_reuse;
9087836SJohn.Forte@Sun.COM 	set->set_free.q_forw = set->set_free.q_back = &set->set_free;
9097836SJohn.Forte@Sun.COM 
9107836SJohn.Forte@Sun.COM 	mutex_enter(&nst_global_lock);
9117836SJohn.Forte@Sun.COM 
9127836SJohn.Forte@Sun.COM 	/* check for duplicates */
9137836SJohn.Forte@Sun.COM 
9147836SJohn.Forte@Sun.COM 	for (sp = nst_sets; sp; sp = sp->set_next) {
9157836SJohn.Forte@Sun.COM 		if (strcmp(sp->set_name, set->set_name) == 0) {
9167836SJohn.Forte@Sun.COM 			/* duplicate */
9177836SJohn.Forte@Sun.COM 			mutex_exit(&nst_global_lock);
9187836SJohn.Forte@Sun.COM 			cv_destroy(&set->set_res_cv);
9197836SJohn.Forte@Sun.COM 			cv_destroy(&set->set_kill_cv);
9207836SJohn.Forte@Sun.COM 			cv_destroy(&set->set_destroy_cv);
9217836SJohn.Forte@Sun.COM 			mutex_destroy(&set->set_lock);
9227836SJohn.Forte@Sun.COM 			kmem_free(set, sizeof (*set));
9237836SJohn.Forte@Sun.COM #ifdef DEBUG
9247836SJohn.Forte@Sun.COM 			cmn_err(CE_WARN,
925*9093SRamana.Srikanth@Sun.COM 			    "!nst_init: duplicate set \"%s\"", name);
9267836SJohn.Forte@Sun.COM #endif
9277836SJohn.Forte@Sun.COM 			/* add threads if necessary */
9287836SJohn.Forte@Sun.COM 
9297836SJohn.Forte@Sun.COM 			if (nthread > sp->set_nthread) {
930*9093SRamana.Srikanth@Sun.COM 				i = nst_add_thread(sp,
931*9093SRamana.Srikanth@Sun.COM 				    nthread - sp->set_nthread);
9327836SJohn.Forte@Sun.COM #ifdef DEBUG
933*9093SRamana.Srikanth@Sun.COM 				if (i !=  (nthread - sp->set_nthread))
934*9093SRamana.Srikanth@Sun.COM 					cmn_err(CE_WARN,
935*9093SRamana.Srikanth@Sun.COM 					    "!nst_init: failed to allocate %d "
936*9093SRamana.Srikanth@Sun.COM 					    "threads (got %d)",
937*9093SRamana.Srikanth@Sun.COM 					    (nthread - sp->set_nthread), i);
9387836SJohn.Forte@Sun.COM #endif
9397836SJohn.Forte@Sun.COM 			}
9407836SJohn.Forte@Sun.COM 
9417836SJohn.Forte@Sun.COM 			/* return pointer to existing set */
9427836SJohn.Forte@Sun.COM 
9437836SJohn.Forte@Sun.COM 			return (sp);
9447836SJohn.Forte@Sun.COM 		}
9457836SJohn.Forte@Sun.COM 	}
9467836SJohn.Forte@Sun.COM 
9477836SJohn.Forte@Sun.COM 	/* add new set to chain */
9487836SJohn.Forte@Sun.COM 	set->set_next = nst_sets;
9497836SJohn.Forte@Sun.COM 	nst_sets = set;
9507836SJohn.Forte@Sun.COM 
9517836SJohn.Forte@Sun.COM 	mutex_exit(&nst_global_lock);
9527836SJohn.Forte@Sun.COM 
9537836SJohn.Forte@Sun.COM 	i = nst_add_thread(set, nthread);
9547836SJohn.Forte@Sun.COM 
9557836SJohn.Forte@Sun.COM 	if (i != nthread) {
9567836SJohn.Forte@Sun.COM #ifdef DEBUG
9577836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN,
958*9093SRamana.Srikanth@Sun.COM 		    "!nst_init: failed to allocate %d threads (got %d)",
959*9093SRamana.Srikanth@Sun.COM 		    nthread, i);
9607836SJohn.Forte@Sun.COM #endif
9617836SJohn.Forte@Sun.COM 		nst_destroy(set);
9627836SJohn.Forte@Sun.COM 		return (NULL);
9637836SJohn.Forte@Sun.COM 	}
9647836SJohn.Forte@Sun.COM 
9657836SJohn.Forte@Sun.COM 	return (set);
9667836SJohn.Forte@Sun.COM }
9677836SJohn.Forte@Sun.COM 
9687836SJohn.Forte@Sun.COM 
9697836SJohn.Forte@Sun.COM /*
9707836SJohn.Forte@Sun.COM  * nst_nlive
9717836SJohn.Forte@Sun.COM  *
9727836SJohn.Forte@Sun.COM  * Return the number of live threads in a set.
9737836SJohn.Forte@Sun.COM  */
9747836SJohn.Forte@Sun.COM int
nst_nlive(nstset_t * set)9757836SJohn.Forte@Sun.COM nst_nlive(nstset_t *set)
9767836SJohn.Forte@Sun.COM {
9777836SJohn.Forte@Sun.COM 	return (set ? set->set_nlive : 0);
9787836SJohn.Forte@Sun.COM }
9797836SJohn.Forte@Sun.COM 
9807836SJohn.Forte@Sun.COM 
9817836SJohn.Forte@Sun.COM /*
9827836SJohn.Forte@Sun.COM  * nst_nthread
9837836SJohn.Forte@Sun.COM  *
9847836SJohn.Forte@Sun.COM  * Return the number of threads in the set.
9857836SJohn.Forte@Sun.COM  */
9867836SJohn.Forte@Sun.COM int
nst_nthread(nstset_t * set)9877836SJohn.Forte@Sun.COM nst_nthread(nstset_t *set)
9887836SJohn.Forte@Sun.COM {
9897836SJohn.Forte@Sun.COM 	return (set ? set->set_nthread : 0);
9907836SJohn.Forte@Sun.COM }
9917836SJohn.Forte@Sun.COM 
9927836SJohn.Forte@Sun.COM 
9937836SJohn.Forte@Sun.COM /*
9947836SJohn.Forte@Sun.COM  * nst_shutdown
9957836SJohn.Forte@Sun.COM  *
9967836SJohn.Forte@Sun.COM  * Called by nskern to shutdown the nsthread software.
9977836SJohn.Forte@Sun.COM  */
9987836SJohn.Forte@Sun.COM void
nst_shutdown(void)9997836SJohn.Forte@Sun.COM nst_shutdown(void)
10007836SJohn.Forte@Sun.COM {
10017836SJohn.Forte@Sun.COM 	nstset_t *set;
10027836SJohn.Forte@Sun.COM 
10037836SJohn.Forte@Sun.COM 	mutex_enter(&nst_global_lock);
10047836SJohn.Forte@Sun.COM 
10057836SJohn.Forte@Sun.COM 	while ((set = nst_sets) != NULL) {
10067836SJohn.Forte@Sun.COM 		mutex_exit(&nst_global_lock);
10077836SJohn.Forte@Sun.COM 		nst_destroy(set);
10087836SJohn.Forte@Sun.COM 		mutex_enter(&nst_global_lock);
10097836SJohn.Forte@Sun.COM 	}
10107836SJohn.Forte@Sun.COM 
10117836SJohn.Forte@Sun.COM 	mutex_exit(&nst_global_lock);
10127836SJohn.Forte@Sun.COM 	mutex_destroy(&nst_global_lock);
10137836SJohn.Forte@Sun.COM }
10147836SJohn.Forte@Sun.COM 
10157836SJohn.Forte@Sun.COM 
10167836SJohn.Forte@Sun.COM /*
10177836SJohn.Forte@Sun.COM  * nst_startup
10187836SJohn.Forte@Sun.COM  *
10197836SJohn.Forte@Sun.COM  * Called by nskern to initialise the nsthread software
10207836SJohn.Forte@Sun.COM  */
10217836SJohn.Forte@Sun.COM int
nst_startup(void)10227836SJohn.Forte@Sun.COM nst_startup(void)
10237836SJohn.Forte@Sun.COM {
10247836SJohn.Forte@Sun.COM 	mutex_init(&nst_global_lock, NULL, MUTEX_DRIVER, NULL);
10257836SJohn.Forte@Sun.COM 	return (0);
10267836SJohn.Forte@Sun.COM }
1027