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