Milán Major

netscape-revival

1 branch
Code

sun-java/md/thread_md.c

#include "sys_api.h"
#include "threads_md.h"
#include "javaThreads.h"
#include "prlog.h"
#include "prglobal.h"
#include "prmon.h"
#include "prdump.h"
#include "finalize.h"
#ifdef XP_MAC
#include <Memory.h>
#endif
/* ID used to distinguish java's thread-private-data */
#define JAVA_TPD_ID 0xcafebabe

int soft_yield_count;

long ProcStackSize = 0;		/* Let machine dependent code pick it */

PRMonitor *pr_threadStartLock;

static char *noname = "_java";

/*
** ASSUMED to be the first thing called!
*/
void intrInit(void)
{
    PR_ASSERT(PR_CurrentThread() != 0);
    pr_threadStartLock = PR_NewNamedMonitor(0, "thread-start-lock");
}

int WaitToDie()
{
    PR_Exit();
#if !defined(XP_PC) || defined(_WIN32)
    PR_NOT_REACHED("Continuing after WaitToDie.");
#endif
    return 0;
}

#ifdef PR_NO_PREEMPT
void PR_CALLBACK force_yield(void *notused)
{
    ExecEnv *ee;
    
    /*	We have to get the ee ourself here... the function EE
    //	checks for NULL and throws an assert, which can actually
    //	happen here.  This is the case when a thread is dying
    //	so eetop gets set to zero, but on the MAC we get pre-empted
    //	and call force_yield.  It is okay to ingnore a NULL
    //	ee in this case because the thread is dying anyway, and
    //	a bonafide yield cannot be far off...
    */
    
    if (threadSelf() == 0)
		ee = DefaultExecEnv;
	else
		ee = (ExecEnv *) THREAD(threadSelf())->eetop;
		
	if (ee && !exceptionOccurred(ee)) {
		ee->exceptionKind = EXCKIND_YIELD;
    }
}
#endif

/*
** Create the primordial thread. It happened when PR_Init is called...
*/
int sysThreadBootstrap(sys_thread_t **tp)
{
    sys_thread_t *t = PR_CurrentThread();
    *tp = t;
    t->dump = sysThreadDumpInfo;
#ifdef PR_NO_PREEMPT
    PR_SetInterruptSwitchHook( (void (*)(void *)) force_yield, 0);
#endif
    return SYS_OK;
}

void sysThreadInitializeSystemThreads(void)
{
    InitializeFinalizerThread();
}

void PR_CALLBACK start_thread(void *o, void *a)
{
    void (*func)(void*) = (void (*)(void*)) o;

    /* Wait for creator thread to Resume us */
    PR_EnterMonitor(pr_threadStartLock);
    PR_ExitMonitor(pr_threadStartLock);

    /* And away we go... */
    (*func)(a);

    /* Bye bye */
    PR_Exit();
}

int sysThreadCreate(long stackSize, uint_t flags, 
		    void *(*func)(void *), 
		    sys_thread_t **tp,
		    void *cookie)
{
    PRThread *t;

#ifdef XP_MAC
	//	Make sure the Mac has at least 96K of
	//	free memory before starting up a thread...
	//	This is part of our "pre-flight" memory
	//	strategy.
	Handle	rainyDayBlock;
	rainyDayBlock = NewHandle(96 * 1024);
	if (rainyDayBlock != NULL)
		DisposeHandle(rainyDayBlock);
	else
		return SYS_NORESOURCE;
#endif

    /*
    ** Create thread at java priority 0. Adjust the java priority for
    ** NSPR priority levels
    */
    t = PR_CreateThread(noname, NormalPriority+10, stackSize);
    if (t) {
	sysThreadSetBackPtr(t, cookie);
	*tp = t;

	if (flags == THR_SYSTEM) {
	    t->flags |= _PR_SYSTEM;	/* XXX bug in NSPR API*/
	}
	/* Use a monitor to force thread to wait for us to resume it */
	PR_EnterMonitor(pr_threadStartLock);
	PR_Start(t, (void (*)(void*,void*))start_thread, func, cookie);
	PR_Suspend(t);
	PR_ExitMonitor(pr_threadStartLock);

	t->dump = sysThreadDumpInfo;

	return SYS_OK;
    }
    *tp = 0;
    return SYS_NORESOURCE;
}

int sysThreadKill(sys_thread_t *t)
{
    PR_DestroyThread(t);
    return SYS_OK;
}

void sysThreadExit(void)
{
    PRThread *t;
    JHandle *p;
    ExecEnv *eep;

    t = PR_CurrentThread();
    p = PR_GetThreadPrivate(t, JAVA_TPD_ID);

    /*
    ** Break association to hardware thread to avoid dangling pointer
    ** problems.
    */
    if (p) {
	THREAD(p)->PrivateInfo = 0;
 
	/* Delete java stack now that we are done with it */
	eep = (ExecEnv *) THREAD(p)->eetop;
	if (eep) {                		/* eep == 0 does happen... */
	    DeleteExecEnv(eep, p);		/* zeros eetop */
	}
    }

    PR_Exit();
}

sys_thread_t *sysThreadSelf(void)
{
    return PR_CurrentThread();
}

void sysThreadYield(void)
{
    PR_Yield();
}

int sysThreadSuspend(sys_thread_t *t)
{
    return PR_Suspend(t);
}

int sysThreadResume(sys_thread_t *t)
{
    /* HACK: reflect java's name for the thread back to NSPR */
    if (t->name &&
	(t->name[0] == '_') &&
	(t->name[1] == 'j') &&
	(t->name[2] == 'a') &&
	(t->name[3] == 'v') &&
	(t->name[4] == 'a') &&
	(t->name[5] == '\0')) {
	TID tid;
	char *name;

	tid = (TID) PR_GetThreadPrivate(t, JAVA_TPD_ID);
	name = Object2CString((JHandle *) THREAD(tid)->name);
	if (name) {
		/* If the thread already has a name, free it. */
		if (t->name)
			sysFree(t->name);
	    t->name = strdup(name);
	}
    }
    return PR_Resume(t);
}

int sysThreadSetPriority(sys_thread_t *t, int32_t n)
{
    int nsprPrio = n + 10;
    PR_ASSERT(java_lang_Thread_MIN_PRIORITY <= n && n <= java_lang_Thread_MAX_PRIORITY);
    PR_ASSERT(nsprPrio < PR_NUM_PRIORITIES);
    PR_SetThreadPriority(t, nsprPrio);
    return SYS_OK;
}

int sysThreadGetPriority(sys_thread_t *t, int32_t *io)
{
    int nsprPrio = PR_GetThreadPriority(t);
    int n = nsprPrio - 10;
    PR_ASSERT(nsprPrio < PR_NUM_PRIORITIES);
    PR_ASSERT(java_lang_Thread_MIN_PRIORITY <= n && n <= java_lang_Thread_MAX_PRIORITY);
    *io = n;
    return SYS_OK;
}

/* XXX bogus: PR_GetSP should deal with current thread */
void *sysThreadStackPointer(sys_thread_t *t)
{
    if (t == PR_CurrentThread()) {
	return (void*) &t;
    } else {
	return (void*) PR_GetSP(t);
    }
}
 
stackp_t sysThreadStackBase(sys_thread_t *t)
{
    return (stackp_t) t->stack;
}
 
#if 0
int sysThreadSingle(void)
{
    PR_SingleThread();
    return SYS_OK;
}

void sysThreadMulti(void)
{
    PR_MultiThread();
}
#endif

struct FooFooStr {
    int (*func)(sys_thread_t *, void *);
    void *arg;
};

static int EnumOneThread(PRThread *t, int i, void *arg)
{
    struct FooFooStr *fp = (struct FooFooStr*) arg;
    void *handle;

    /* Only scan over java threads (skip the non-java threads) */
    handle = PR_GetThreadPrivate(t, JAVA_TPD_ID);
    if (handle) {
	return (*fp->func)(t, fp->arg);
    }
    return 1;
}

int sysThreadEnumerateOver(int (*func)(sys_thread_t *, void *), void *arg)
{
    struct FooFooStr foo;

    foo.func = func;
    foo.arg = arg;
    PR_EnumerateThreads(EnumOneThread, &foo);
    return SYS_OK;
}

void sysThreadSetBackPtr(sys_thread_t *t, void *cookie)
{
    if (!PR_SetThreadPrivate(t, JAVA_TPD_ID, cookie)) {
	/* Ran out of memory ! */
	abort();/* XXX */
    }
}

void *sysThreadGetBackPtr(sys_thread_t *t)
{
    return PR_GetThreadPrivate(t, JAVA_TPD_ID);
}

void sysThreadInit(sys_thread_t *t, stackp_t sb)
{
}

int sysThreadCheckStack(void)
{
    /* XXX stack is always... OK */
    return 1;
}

void
sysThreadPostException(sys_thread_t *t, void *exc) 
{ 
    TID tid;
    struct execenv *ee;

    tid = (TID) PR_GetThreadPrivate(t, JAVA_TPD_ID);

#if 0
    {
	char *name = t->name;

	if (name == noname) {
	    /* Get java's name */
	    name = Object2CString((JHandle *) THREAD(tid)->name);
	}
	fprintf(stderr,
	   "attempting to kill thread %s using sysThreadPostException...\n",
	   name);
    }
#endif

    ee = (ExecEnv *) THREAD(tid)->eetop;
    PR_ASSERT(ee != 0);

    if (ee != (ExecEnv *) 0) {   
	exceptionThrow(ee, (JHandle*) exc);
    }
    PR_SetPendingException(t);
    PR_Yield();
} 

JAVA_PUBLIC_API(void)
sysThreadDumpInfo(sys_thread_t* t, FILE* out)
{
    TID tid = (TID)sysThreadGetBackPtr(t);
    if (tid)
    {
	JavaFrame* frame;
	struct Classjava_lang_Thread* thread = THREAD(tid);
	ExecEnv* ee = (ExecEnv*)thread->eetop;
	struct Hjava_lang_ThreadGroup* group = thread->group;
	if (group)
	{
	    char name[256];
	    javaString2CString(unhand(group)->name, name, sizeof(name));
	    fprintf(out, "    in group %s\n", name);
	}
	else {
	    fprintf(out, "    no group\n");
	}
	if (ee) {
	    for (frame = ee->current_frame; frame != NULL; frame = frame->prev)
	    {
		char where[256];
		pc2string(frame->lastpc, 0, where, where + sizeof(where));
		fprintf(out, "\t%s\n", where);
	    }
	}
    }
}