/*
 * sthreads_null.c
 *
 * defines
 *    mythread
 *    sthread_init
 *    sthread_got_exception
 *    sthread_create
 *    sthread_stop
 *    sthread_yield
 *    sthread_sleep
 *    sthread_suspend
 *    sthread_resume
 *    sthread_setpriority
 *    sthread_current
 *    sthread_exit
 *    sthread_dontkill_start
 *    sthread_dontkill_end
 *    sthread_mutex_init
 *    sthread_mutex_lock
 *    sthread_mutex_unlock
 *    sthread_mutex_destroy
 *    sthread_cond_init
 *    sthread_cond_wait
 *    sthread_cond_signal
 *    sthread_cond_broadcast
 *    sthread_cond_destroy
 * 
 * TO DO:
 *   - There is some code in here that is not dependent
 *     on the underlying threads package - it should probably
 *     be broken out
 *
 * NOTE: We use the (otherwise unused) threadQ field of
 *       a java.lang.Thread to point to a thread's TCB
 */

#include <stdio.h>
#include <stddef.h>
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/time.h>

#include "toba.h"
#include "sthreads.h"
#include "runtime.h"

#include "java_lang_Object.h"
#include "java_lang_Thread.h"
#include "java_lang_ThreadGroup.h"
#include "java_lang_IllegalThreadStateException.h"

/* single threaded flag and the single threads tcb */
int singlethreaded = 1;
static tcb *onlythread;


void
sthread_got_exception(void)
{
}

/*
 * Initialization of thread system
 */
void
sthread_init(void) 
{
    tcb *newtcb;
    struct in_java_lang_Thread *obj;
    struct in_java_lang_ThreadGroup *sysgroup;

    /* Start up singlethreaded */
    singlethreaded = 1;

    /* create a java.lang.Thread object and a thread group
     * for this thread */
    newtcb = (tcb *)allocate(sizeof(*newtcb));

    /* associate the TCB with this thread */
    onlythread = newtcb;

    /* defer asynchronous actions until we're ready for them */
    newtcb->defer = 1;
    newtcb->state = TS_RUNNING;

    /* new ThreadGroup() */
    sysgroup = new(&cl_java_lang_ThreadGroup.C);
    init__UzqJE(sysgroup);

    /* new Thread(group, runnable, string) */
    obj = new(&cl_java_lang_Thread.C);
    newtcb->obj = obj;
    init_TRS_jtRvs(obj, sysgroup, obj, javastring("main"));

    /* XXX main should have its own thread group */

    /* the thread is still not killable yet - 
     * the lock is held until default exception
     * handling is set up in start_thread() */

}

/* Note that this routine runs prior to calling sthread_init */
void
sthread_launch(void (*routine)(void *arg), void *arg)
{
   /* Dispatch to the named routine */
   (*routine)(arg);

   /*NOTREACHED*/
}

/*
 * create a new thread associated with this java.lang.Thread object
 * and start it running in its start method
 */
void
sthread_create(struct in_java_lang_Thread *o)
/*ARGSUSED*/
{
    unimpl("sthread_create");
}

/*
 * Retrieve per-thread state
 */
tcb *
sthread_current()
{
    return onlythread;
}

struct mythread *
mythread()
{
    return &sthread_current()->mythread;
}

void
sthread_yield()
{
    unimpl("sthread_yield");
}

void
sthread_sleep(Long millis)
{
    struct timeval tv;

    tv.tv_sec = millis / 1000;
    tv.tv_usec = (millis % 1000) * 1000;
    select(0, 0, 0, 0, &tv);
}

void
sthread_suspend(struct in_java_lang_Thread *o)
/*ARGSUSED*/
{
    unimpl("sthread_suspend");
}

void
sthread_resume(struct in_java_lang_Thread *o)
/*ARGSUSED*/
{
    unimpl("sthread_resume");
}

void
sthread_setpriority(struct in_java_lang_Thread *o, int priority)
/*ARGSUSED*/
{
    /* no threads - nop */
}

void
sthread_stop(struct in_java_lang_Thread *o, Object e)
/*ARGSUSED*/
{
    unimpl("sthread_stop");
}

/*
 * wait for all non-daemon threads to exit
 */
void
sthread_exit()
{
    /* we're the only thread - no waiting */
}

/* start a sequence in which a thread shouldn't be killed */
void
sthread_dontkill_start(struct mythread *thr)
/*ARGSUSED*/
{
}

/* end a sequence in which a thread shouldn't be killed */
void
sthread_dontkill_end(struct mythread *thr)
/*ARGSUSED*/
{
}

int
sthread_dontkill_p(struct mythread *thr)
/*ARGSUSED*/
{
    return 0;
}

void
sthread_mutex_init(struct sthread_mutex *m)
/*ARGSUSED*/
{
}

void
sthread_mutex_lock(struct sthread_mutex *m)
/*ARGSUSED*/
{
}

void
sthread_mutex_unlock(struct sthread_mutex *m)
/*ARGSUSED*/
{
}

void
sthread_mutex_destroy(struct sthread_mutex *m)
/*ARGSUSED*/
{
}

void
sthread_cond_init(struct sthread_cond *c)
/*ARGSUSED*/
{
}

void
sthread_cond_wait(struct sthread_cond *c, struct sthread_mutex *m, 
		  Long timeout)
/*ARGSUSED*/
{
    unimpl("sthread_cond_wait");
}

void
sthread_cond_signal(struct sthread_cond *c) 
/*ARGSUSED*/
{
}

void
sthread_cond_broadcast(struct sthread_cond *c)
/*ARGSUSED*/
{
}

void
sthread_cond_destroy(struct sthread_cond *c)
/*ARGSUSED*/
{
}
