/*
 * $Id: uthread.c,v 1.1 2000/08/07 23:15:04 emmerson Exp $
 *
 * UNIDATA/POSIX threads support.
 */

#include <stddef.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>

#include "uthread.h"

#ifndef UD_THREAD_FSU_6

static int		initialized;
static uthread_attr_t	default_attr;


    int
uthread_attr_init(attr)
    uthread_attr_t	*attr;
{
    int		status = 0;		/* success */

    assert(initialized);

    if (attr) {
	*attr	= default_attr;
    } else {
	errno	= EINVAL;
	status	= -1;
    }

    return status;
}


    int
uthread_attr_setdetachstate(attr, yes)
    uthread_attr_t	*attr;
    int			*yes;
{
    int			status = 0;	/* success */

    assert(initialized);

    if (!attr || !yes) {
	errno	= EINVAL;
	status	= -1;
    } else {
#       ifdef UD_THREAD_SUNOS_5
	    if (*yes)
		attr->flags	|= THR_DETACHED;
	    else
		attr->flags	&= ~THR_DETACHED;
#       endif

#       ifdef UD_THREAD_DEC_4
	    attr->detach_state	= *yes;
#       endif
    }

    return status;
}


    int
uthread_attr_getstacksize(attr, stacksize)
    uthread_attr_t	*attr;
    size_t		*stacksize;
{
    int			status = 0;	/* success */

    assert(initialized);

    if (attr && stacksize) {
#	ifdef UD_THREAD_SUNOS_5
	    *stacksize	= thr_min_stack();
#	endif
#       ifdef UD_THREAD_DEC_4
	    *stacksize	= pthread_attr_getstacksize(attr->attr);
#       endif
    } else {
	errno	= EINVAL;
	status	= -1;
    }

    return status;
}


    int
uthread_attr_setstacksize(attr, stacksize)
    uthread_attr_t	*attr;
    size_t		stacksize;
{
    int			status = 0;	/* success */

    assert(initialized);

#   ifdef UD_THREAD_SUNOS_5
	if (attr && (stacksize == 0 || stacksize >= thr_min_stack())) {
	    attr->stacksize	= stacksize;
#   endif
#   ifdef UD_THREAD_DEC_4
	if (attr) {
	    status	= pthread_attr_setstacksize(&attr->attr,
						    (int) stacksize);
#   endif
    } else {
	errno	= EINVAL;
	status	= -1;
    }

    return status;
}


    int
uthread_attr_setprio(attr, priority)
    uthread_attr_t	*attr;
    int			priority;
{
    int			status = 0;	/* success */

    assert(initialized);

#   ifdef UD_THREAD_SUNOS_5
	attr->priority	= priority;
#   endif

#   ifdef UD_THREAD_DEC_4
	status	= pthread_attr_setprio(&attr->attr, priority);
#   endif

    return status;
}


#ifdef UD_THREAD_DEC_4
    int
uthread_cond_init(cond, condattr)
    uthread_cond_t	*cond;
    uthread_condattr_t	*condattr;
{
    assert(initialized);

    assert(0 == condattr);

    return pthread_cond_init(cond, pthread_condattr_default);
}
#endif


#include <sys/time.h>
#include <sys/resource.h>


    int
uthread_create(thread, attr, start_func, arg)
    uthread_t           *thread;
    uthread_attr_t      *attr;
    uthread_func_t       start_func;
    void                *arg;
{
    int			status = 0;	/* success */

    assert(initialized);

#   ifdef UD_THREAD_SUNOS_5
    {
	int		orig_priority;

	if (NULL == attr)
	    attr	= &default_attr;

	status	= thr_getprio(thr_self(), &orig_priority);
	assert(0 == status);

	errno = 0;
	status	= thr_create((void*)0,
			     attr->stacksize,
			     start_func,
			     arg, 
			     attr->flags | THR_SUSPENDED,
			     thread);

	if (status) {
	    errno = status;
	    status = -1;
	} else {
	    if (orig_priority != attr->priority)
		(void) thr_setprio(*thread, attr->priority);
	    (void) thr_continue(*thread);
	}
    }
#   endif

#   ifdef UD_THREAD_DEC_4
	if (NULL == attr)
	    attr	= &default_attr;

	status	= pthread_create(thread, attr->attr, start_func, arg);

	if (0 == status && attr->detach_state)
	    status	= pthread_detach(thread);
#   endif

    return status;
}


    int
uthread_init()
{
    int		status = 0;		/* success */

    if (!initialized) {
#	ifdef UD_THREAD_SUNOS_5
	    default_attr.flags	= 0;
	    status	= thr_getprio(thr_self(), &default_attr.priority);
	    assert(0 == status);
#	endif

#       ifdef UD_THREAD_DEC_4
	    default_attr.detach_state	= 0;
	    status	= pthread_attr_create(&default_attr.attr);
	    assert(0 == status);
#	endif

	initialized	= 1;
#ifdef PURIFY
	purify_watch(&initialized);
#endif
    }

    return status;
}


    int
uthread_yield(ptr)
    /*ARGSUSED*/
    voidp	ptr;
{
    assert(0 == ptr);

    assert(initialized);

#   ifdef UD_THREAD_SUNOS_5
	thr_yield();
#   endif

#   ifdef UD_THREAD_DEC_4
	pthread_yield();
#   endif

    return 0;
}

#endif	/* not FSU's Draft 6 Pthreads implementation */
