fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * CDDL HEADER START
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * The contents of this file are subject to the terms of the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Common Development and Distribution License (the "License").
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * You may not use this file except in compliance with the License.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * See the License for the specific language governing permissions
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * and limitations under the License.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * When distributing Covered Code, include this CDDL HEADER in each
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If applicable, add the following below this CDDL HEADER, with the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fields enclosed by brackets "[]" replaced with your own identifying
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * information: Portions Copyright [yyyy] [name of copyright owner]
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * CDDL HEADER END
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Use is subject to license terms.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Global data
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic kmutex_t nst_global_lock; /* nst_sets, nst_pending */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * nst_kmem_xalloc
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Poll for memory.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic void *
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortenst_kmem_xalloc(size_t size, int sec, void *(*alloc)(size_t, int))
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte while (usec > 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte delay(drv_usectohz((clock_t)NST_MEMORY_TIMEOUT));
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana cmn_err(CE_WARN, "!nst_kmem_xalloc: failed to alloc %ld bytes", size);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte/* currently unused */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic void *
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic void *
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return (nst_kmem_xalloc(size, sec, kmem_zalloc));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Queue stuff that should be in the DDI.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * nst_insque
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Insert entryp after predp in a doubly linked list.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#pragma inline(nst_insque) /* compiler hint to inline this function */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * nst_remque
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Remove entryp from a doubly linked list.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#pragma inline(nst_remque) /* compiler hint to inline this function */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * nst_thread_init
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Initialise the dynamic part of a thread
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#pragma inline(nst_thread_init) /* compiler hint to inline this function */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * nst_thread_alloc
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Return an nsthread from the free pool, NULL if none
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(nst_thread_alloc_err_kill, nstset_t *, set);
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE2(nst_thread_alloc_sleep, nstset_t *, set,
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(nst_thread_alloc_wake, nstset_t *, set);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* initialise the thread */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * nst_thread_free
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Requeue a thread on the free or reuse pools. Threads are always
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * queued to the tail of the list to prevent rapid recycling.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Must be called with set->set_lock held.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* add self to reuse pool */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* add self to free pool */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * nst_thread_run
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * The first function that a new thread runs on entry from user land.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * This is the main thread function that handles thread work and death.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* check if this thread is still on the pending list */
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana cmn_err(CE_WARN, "!nst_thread_run(%p): already dead?",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* check that the set is still on the list of sets */
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana cmn_err(CE_WARN, "!nst_thread_run(%p): no set?", (void *)tp);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Mark the parent.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * The parent won't actually run until set->set_lock is dropped.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Main loop.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * On initial entry the caller will add this thread to
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * the free pool if required, there after the thread
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * must do it for itself.
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(nst_thread_run_sleep, nsthread_t *, tp);
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(nst_thread_run_wake, nsthread_t *, tp);
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana "!nst_thread_run(%p): NULL function pointer",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* remove self from the free and/or reuse pools */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (tp->tp_link.q_forw != NULL || tp->tp_link.q_back != NULL) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* wake the context that is running nst_destroy() or nst_del_thread() */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* suicide */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * nst_thread_destroy
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Free up the kernel level resources. The thread must already be
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * un-chained from the set, and the caller must not be the thread
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana cmn_err(CE_WARN, "!nst_thread_destroy(%p): still in use!",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* leak the thread */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * nst_thread_create
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Create and return a new thread from a threadset.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* try and reuse a thread first */
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE2(nst_thread_create_end, nstset_t *, set,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* create a thread using nskernd */
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(nst_thread_create_err_mem, nstset_t *, set);
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana cmn_err(CE_WARN, "!nst_thread_create: called during destroy");
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE2(nst_thread_create_err_kill, nstset_t *, set,
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE2(nst_dbg_thr_create_proc_start, nstset_t *, set,
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE2(nst_dbg_thr_create_proc_end, nstset_t *, set,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * wait for child to start and check in.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * remove from pending chain.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (tpp = &nst_pending; (*tpp); tpp = &((*tpp)->tp_chain)) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Check for errors and return if required.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (rc == 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Thread is alive, and needs to be woken and killed.
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana "!nst_thread_create: error (rc %d, set_flag %x, "
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana "set_nthread %d)", rc, set->set_flag, set->set_nthread);
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE2(nst_thread_create_err_proc, nstset_t *, set,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Move into set proper.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * nst_create
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Start a new thread from a thread set, returning the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * address of the thread, or NULL on failure.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * All threads are created detached.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Valid flag values:
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * NST_CREATE - create a new thread rather than using one
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * from the threadset. Once the thread
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * completes it will not be added to the active
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * portion of the threadset, but will be cached
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * on the reuse chain, and so is available for
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * subsequent NST_CREATE or nst_add_thread()
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * operations.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * NST_SLEEP - wait for a thread to be available instead of
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * returning NULL. Has no meaning with NST_CREATE.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Returns a pointer to the new thread, or NULL.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortenst_create(nstset_t *set, void (*func)(), blind_t arg, int flags)
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(nst_create_err_kill, nstset_t *, set);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* get new thread */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* initialise the thread */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (!(tp = nst_thread_alloc(set, (flags & NST_SLEEP))))
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* set thread running */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * nst_destroy
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Destroy a thread set created by nst_init(). It is the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * caller's responsibility to ensure that all prior thread
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * calls have completed prior to this call and that the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * caller is not executing from within thread context.
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana cmn_err(CE_WARN, "!nst_destroy(%p): no set?", (void *)set);
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(nst_destroy_err_noset, nstset_t *, set);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Wait for a pending destroy to complete
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana "!nst_destroy(%p): duplicate destroy of set", (void *)set);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte (void) cv_wait_sig(&set->set_destroy_cv, &set->set_lock);
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(nst_destroy_end, nstset_t *, set);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Wake all threads in nst_create(NST_SLEEP) */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Wake all the threads chained in the set.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Wait for the threads to exit */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte while ((set->set_free.q_forw != &set->set_free) ||
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Unchain and destroy all the threads in the set */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* remove the set from the chain */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (spp = &nst_sets; *spp; spp = &((*spp)->set_next)) {
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana cmn_err(CE_WARN, "!nst_destroy(%p): nthread != 0 (%d)",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Allow any waiters (above) to continue */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte while (set->set_destroy_cnt > 0 || set->set_pending > 0 ||
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* leak the set control structure */
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(nst_destroy_end, nstset_t *, set);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * nst_add_thread
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Add more threads into an existing thread set.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Returns the number successfully added.
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana "!nst_add_thread(%p, %d) - bad args", (void *)set, nthread);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (i = 0; i < nthread; i++) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* get new thread */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* add to free list */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * nst_del_thread
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Removes threads from an existing thread set.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Returns the number successfully removed.
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana "!nst_del_thread(%p, %d) - bad args", (void *)set, nthread);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (i = 0; i < nthread; i++) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* get thread */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* unlink from the set */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (tpp = &set->set_chain; *tpp; tpp = &(*tpp)->tp_chain) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* kill the thread */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* wait for thread to exit */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* free kernel resources */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Initialise a new nsthread set, returning its address or
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * NULL in the event of failure. The set should be destroyed
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * by calling nst_destroy().
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana cmn_err(CE_WARN, "!nst_init: invalid arg");
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana cmn_err(CE_WARN, "!nst_init: arg limit exceeded");
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte mutex_init(&set->set_lock, NULL, MUTEX_DRIVER, NULL);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte cv_init(&set->set_destroy_cv, NULL, CV_DRIVER, NULL);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte cv_init(&set->set_kill_cv, NULL, CV_DRIVER, NULL);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte cv_init(&set->set_res_cv, NULL, CV_DRIVER, NULL);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte set->set_reuse.q_forw = set->set_reuse.q_back = &set->set_reuse;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte set->set_free.q_forw = set->set_free.q_back = &set->set_free;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* check for duplicates */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* duplicate */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* add threads if necessary */
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana "!nst_init: failed to allocate %d "
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana "threads (got %d)",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* return pointer to existing set */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* add new set to chain */
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana "!nst_init: failed to allocate %d threads (got %d)",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Return the number of live threads in a set.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * nst_nthread
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Return the number of threads in the set.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * nst_shutdown
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Called by nskern to shutdown the nsthread software.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * nst_startup
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Called by nskern to initialise the nsthread software