/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include "nsc_thread.h"
#ifdef DS_DDICT
#include "../contract.h"
#endif
#include "../nsctl.h"
#include "nskernd.h"
/*
* Global data
*/
/*
* nst_kmem_xalloc
*
* Poll for memory.
*/
static void *
{
void *p = NULL;
while (usec > 0) {
return (p);
}
return (NULL);
}
#if 0
/* currently unused */
static void *
{
}
#endif
static void *
{
}
/*
* Queue stuff that should be in the DDI.
*/
/*
* nst_insque
*
* Insert entryp after predp in a doubly linked list.
*/
static void
{
}
#ifndef DS_DDICT
#pragma inline(nst_insque) /* compiler hint to inline this function */
#endif
/*
* nst_remque
*
* Remove entryp from a doubly linked list.
*/
static void
{
}
#ifndef DS_DDICT
#pragma inline(nst_remque) /* compiler hint to inline this function */
#endif
/*
* nst_thread_init
*
* Initialise the dynamic part of a thread
*/
static void
{
}
#ifndef DS_DDICT
#pragma inline(nst_thread_init) /* compiler hint to inline this function */
#endif
/*
* nst_thread_alloc
*
* Return an nsthread from the free pool, NULL if none
*/
static nsthread_t *
{
return (NULL);
}
do {
else {
if (!sleep)
break;
set->set_res_cnt++;
int, set->set_res_cnt);
set->set_res_cnt--;
break;
}
/* initialise the thread */
}
return (tp);
}
/*
* nst_thread_free
*
* Requeue a thread on the free or reuse pools. Threads are always
* queued to the tail of the list to prevent rapid recycling.
*
* Must be called with set->set_lock held.
*/
static void
{
if (!set)
return;
/* add self to reuse pool */
} else {
/* add self to free pool */
if (set->set_res_cnt > 0)
}
}
/*
* nst_thread_run
*
* The first function that a new thread runs on entry from user land.
* This is the main thread function that handles thread work and death.
*/
static void
{
/* check if this thread is still on the pending list */
break;
}
}
if (!tp) {
return;
}
#ifdef DEBUG
(void *)tp);
#endif
return;
}
/* check that the set is still on the list of sets */
break;
}
}
if (!set) {
#ifdef DEBUG
#endif
return;
}
/*
* Mark the parent.
* The parent won't actually run until set->set_lock is dropped.
*/
/*
* Main loop.
*/
/*
* On initial entry the caller will add this thread to
* the free pool if required, there after the thread
* must do it for itself.
*/
if (first) {
first = 0;
} else {
}
break;
}
}
#ifdef DEBUG
else {
"!nst_thread_run(%p): NULL function pointer",
(void *)tp);
}
#endif
}
}
set->set_nthread--;
/* wake the context that is running nst_destroy() or nst_del_thread() */
/* suicide */
}
/*
* nst_thread_destroy
*
* Free up the kernel level resources. The thread must already be
* un-chained from the set, and the caller must not be the thread
* itself.
*/
static void
{
if (!tp)
return;
(void *)tp);
/* leak the thread */
return;
}
}
/*
* nst_thread_create
*
* Create and return a new thread from a threadset.
*/
static nsthread_t *
{
int rc;
/* try and reuse a thread first */
else
if (tp) {
nsthread_t *, tp);
return (tp);
}
}
/* create a thread using nskernd */
if (!tp) {
return (NULL);
}
#ifdef DEBUG
#endif
nsthread_t *, tp);
return (NULL);
}
set->set_pending++;
nst_pending = tp;
nsthread_t *, tp);
nsthread_t *, tp);
if (!rc) {
/*
* wait for child to start and check in.
*/
}
/*
* remove from pending chain.
*/
break;
}
}
/*
* Check for errors and return if required.
*/
set->set_pending--;
if (rc ||
if (rc == 0) {
/*
* Thread is alive, and needs to be woken and killed.
*/
}
#ifdef DEBUG
"!nst_thread_create: error (rc %d, set_flag %x, "
#endif
nsthread_t *, tp);
return (NULL);
}
/*
* Move into set proper.
*/
set->set_nthread++;
return (tp);
}
/*
* nst_create
*
* Start a new thread from a thread set, returning the
* address of the thread, or NULL on failure.
*
* All threads are created detached.
*
* Valid flag values:
*
* NST_CREATE - create a new thread rather than using one
* from the threadset. Once the thread
* completes it will not be added to the active
* portion of the threadset, but will be cached
* on the reuse chain, and so is available for
* subsequent NST_CREATE or nst_add_thread()
* operations.
*
* NST_SLEEP - wait for a thread to be available instead of
* returning NULL. Has no meaning with NST_CREATE.
*
* Returns a pointer to the new thread, or NULL.
*/
{
if (!set)
return (NULL);
return (NULL);
}
if (flags & NST_CREATE) {
/* get new thread */
return (NULL);
/* initialise the thread */
} else {
return (NULL);
}
/* set thread running */
return (tp);
}
/*
* nst_destroy
*
* Destroy a thread set created by nst_init(). It is the
* caller's responsibility to ensure that all prior thread
* calls have completed prior to this call and that the
* caller is not executing from within thread context.
*/
void
{
if (!set)
return;
break;
}
}
if (!sp) {
#ifdef DEBUG
#endif
return;
}
/*
* Wait for a pending destroy to complete
*/
#ifdef DEBUG
"!nst_destroy(%p): duplicate destroy of set", (void *)set);
#endif
set->set_destroy_cnt++;
set->set_destroy_cnt--;
return;
}
/* Wake all threads in nst_create(NST_SLEEP) */
/*
* Wake all the threads chained in the set.
*/
/* Wait for the threads to exit */
/* Unchain and destroy all the threads in the set */
while (tp) {
}
/* remove the set from the chain */
break;
}
}
#ifdef DEBUG
if (set->set_nthread != 0) {
}
#endif
/* Allow any waiters (above) to continue */
set->set_res_cnt > 0) {
}
if (set->set_nthread != 0) {
/* leak the set control structure */
return;
}
}
/*
* nst_add_thread
*
* Add more threads into an existing thread set.
* Returns the number successfully added.
*/
int
{
int i;
#ifdef DEBUG
#endif
return (0);
}
for (i = 0; i < nthread; i++) {
/* get new thread */
break;
/* add to free list */
}
return (i);
}
/*
* nst_del_thread
*
* Removes threads from an existing thread set.
* Returns the number successfully removed.
*/
int
{
int i;
#ifdef DEBUG
#endif
return (0);
}
for (i = 0; i < nthread; i++) {
/* get thread */
break;
/* unlink from the set */
break;
}
}
/* kill the thread */
/* wait for thread to exit */
/* free kernel resources */
}
return (i);
}
/*
* nst_init
*
* Initialise a new nsthread set, returning its address or
* NULL in the event of failure. The set should be destroyed
* by calling nst_destroy().
*/
nstset_t *
{
int len, i;
if (nthread < 1) {
#ifdef DEBUG
#endif
return (NULL);
}
#ifdef DEBUG
#endif
return (NULL);
}
return (NULL);
/* check for duplicates */
/* duplicate */
#ifdef DEBUG
"!nst_init: duplicate set \"%s\"", name);
#endif
/* add threads if necessary */
i = nst_add_thread(sp,
#ifdef DEBUG
"!nst_init: failed to allocate %d "
"threads (got %d)",
#endif
}
/* return pointer to existing set */
return (sp);
}
}
/* add new set to chain */
if (i != nthread) {
#ifdef DEBUG
"!nst_init: failed to allocate %d threads (got %d)",
nthread, i);
#endif
return (NULL);
}
return (set);
}
/*
* nst_nlive
*
* Return the number of live threads in a set.
*/
int
{
}
/*
* nst_nthread
*
* Return the number of threads in the set.
*/
int
{
}
/*
* nst_shutdown
*
* Called by nskern to shutdown the nsthread software.
*/
void
nst_shutdown(void)
{
}
}
/*
* nst_startup
*
* Called by nskern to initialise the nsthread software
*/
int
nst_startup(void)
{
return (0);
}