thread.c

来自「基于LWVCL开发的库」· C语言 代码 · 共 793 行 · 第 1/2 页

C
793
字号
/* * thread.c * Thread support. * * Copyright (c) 1996, 1997 *	Transvirtual Technologies, Inc.  All rights reserved. * * Copyright (c) 2004 *      The Kaffe.org's developers. See ChangeLog for details. * * See the file "license.terms" for information on usage and redistribution  * of this file.  */#include "config.h"#ifdef HAVE_SYS_TYPES_H#include <sys/types.h>#endif#ifdef HAVE_SYS_TIME_H#include <sys/time.h>#endif#if defined(HAVE_SYS_RESOURCE_H)#include <sys/resource.h>#endif#include "debug.h"#include "config-std.h"#include "config-mem.h"#include "config-io.h"#include "config-signal.h"#include "jni_md.h"#include "gtypes.h"#include "access.h"#include "object.h"#include "constants.h"#include "errors.h"#include "classMethod.h"#include "baseClasses.h"#include "stringSupport.h"#include "lookup.h"#include "thread.h"#include "jthread.h"#include "locks.h"#include "ksem.h"#include "exception.h"#include "support.h"#include "external.h"#include "gc.h"#include "jni.h"#include "md.h"#include "jvmpi_kaffe.h"/* If not otherwise specified, assume at least 1MB for main thread */#ifndef MAINSTACKSIZE#define MAINSTACKSIZE (1024*1024)#endif		extern struct JNINativeInterface Kaffe_JNINativeInterface;static size_t threadStackSize;	/* native stack size *//* referenced by native/Runtime.c */jboolean runFinalizerOnExit;	/* should we run finalizers? */static jboolean deadlockDetection = 1;	/* abort if we detect deadlock *//** * Turn deadlock detection on or off. * * @param detect 0 to turn detection off, !0 to turn it on. */void KaffeVM_setDeadlockDetection(jboolean detect) {  deadlockDetection = detect;}Hjava_lang_Class* ThreadClass;Hjava_lang_Class* VMThreadClass;Hjava_lang_Class* ThreadGroupClass;static void firstStartThread(void*);static void runfinalizer(void);static voidlinkNativeAndJavaThread(jthread_t thread, Hjava_lang_VMThread *jlThread){	jnirefs *reftable;	threadData *thread_data = KTHREAD(get_data)(thread);	thread_data->jlThread = jlThread;	unhand (jlThread)->vmdata = (struct Horg_kaffe_util_Ptr *)thread;	thread_data->jnireferences = NULL;	thread_data->jniEnv = &Kaffe_JNINativeInterface;	thread_data->needOnStack = STACK_HIGH; 	/* Setup JNI for this newly attached thread */	reftable = (jnirefs *)gc_malloc(sizeof(jnirefs) + sizeof(jref) * DEFAULT_JNIREFS_NUMBER,					KGC_ALLOC_STATIC_THREADDATA);	reftable->frameSize = DEFAULT_JNIREFS_NUMBER;	reftable->localFrames = 1;	thread_data->jnireferences = reftable;}/* * Destroys current thread's heavy lock and resets jniEnv. Called from * the threading implementation before a thread is destroyed or reused. */voidKaffeVM_unlinkNativeAndJavaThread(void){	jthread_t thread = KTHREAD(current)();	threadData *thread_data = KTHREAD(get_data)(thread);	thread_data->jniEnv = NULL;	KSEM(destroy) (&thread_data->sem);}/* * Initialise threads. */voidinitThreads(void){	errorInfo info;	DBG(INIT, dprintf("initThreads()\n"); );	/* Get a handle on the thread and thread group classes */	ThreadClass = lookupClass(THREADCLASS, NULL, &info);	assert(ThreadClass != 0);	VMThreadClass = lookupClass(VMTHREADCLASS, NULL, &info);	assert(VMThreadClass != 0);	ThreadGroupClass = lookupClass(THREADGROUPCLASS, NULL, &info);	assert(ThreadGroupClass != 0);	/* Allocate a thread to be the main thread */	KaffeVM_attachFakedThreadInstance("main", false);	DBG(INIT, dprintf("initThreads() done\n"); );}static jthread_tcreateThread(Hjava_lang_VMThread* vmtid, void (*func)(void *), void *arg,	     size_t stacksize,	     struct _errorInfo *einfo){	jthread_t nativeThread;	Hjava_lang_Thread* tid = unhand(vmtid)->thread;	nativeThread = 	  KTHREAD(create)(((unsigned char)unhand(tid)->priority),			 func,			 unhand(tid)->daemon,			 arg,			 stacksize);	if (nativeThread == NULL) {		postOutOfMemory(einfo);		return NULL;	}		return nativeThread;}/* * Start a new thread running. */voidstartThread(Hjava_lang_VMThread* tid){	jthread_t nativeTid;	struct _errorInfo info;	int r;DBG(VMTHREAD, dprintf ("%p starting thread %p (vmthread %p)\n\n", KTHREAD(current)(), unhand(tid)->thread, tid); );	/* Hold the start lock while the thread is created.	 * This lock prevents the new thread from running until we're	 * finished in create.	 * See also firstStartThread.	 */	nativeTid = createThread(tid, &firstStartThread,				 KTHREAD(current)(),				 threadStackSize, &info);	if (nativeTid == NULL) {		throwError(&info);	}	do {	  r = KSEM(get)(&THREAD_DATA()->sem, (jlong)0);	} while (!r);	linkNativeAndJavaThread (nativeTid, tid);	KSEM(put)(&KTHREAD(get_data)(nativeTid)->sem);}/* * Interrupt a thread */voidinterruptThread(Hjava_lang_VMThread* tid){DBG(VMTHREAD, dprintf ("%p (%p) interrupting %p (%p)\n", KTHREAD(current)(),                       THREAD_DATA()->jlThread, unhand(tid)->vmdata, tid); );	assert(unhand(tid)->vmdata != NULL);	KTHREAD(interrupt)((jthread_t)unhand(tid)->vmdata);}/* * Stop a thread from running and terminate it. */voidstopThread(Hjava_lang_VMThread* tid, Hjava_lang_Object* obj){	if (getCurrentThread() == unhand(tid)->thread) {		throwException((Hjava_lang_Throwable*)obj);	}	else {		/*		 * Note that we deviate from the spec here in that the target 		 * thread won't throw the exception `obj', but it will 		 * construct a new ThreadDeath exception when it dies.		 */		if ((jthread_t)unhand(tid)->vmdata)			KTHREAD(stop)((jthread_t)unhand(tid)->vmdata);	}}/** * Detach this thread from the VM. * This must not be called only when the thread has left the VM * completely (e.g. the native code must not return in the interpreter/JIT * after that). */void KaffeVM_detachCurrentThread(){  Hjava_lang_Thread* tid = getCurrentThread();  DBG(VMTHREAD, dprintf("detachThreadInstance(%p, %s)\n", tid, nameThread(unhand(tid)->vmThread)); );  KaffeVM_unlinkNativeAndJavaThread();}/** * Attach an external thread to the VM. * We should only ever call this once for each external thread. * (Note: All assertions on that must have been checked before) */voidKaffeVM_attachFakedThreadInstance(const char* nm, int isDaemon){	Hjava_lang_Thread* tid;	jvalue retval;	int i;	DBG(VMTHREAD, dprintf("attachFakedThreadInstance(%s)\n", nm); );	/* Allocate a thread to be the main thread */	tid = (Hjava_lang_Thread*)newObject(ThreadClass);	assert(tid != 0);	unhand(tid)->name = stringC2Java(nm);	assert(unhand(tid)->name != NULL);	unhand(tid)->priority = java_lang_Thread_NORM_PRIORITY;	unhand(tid)->daemon = isDaemon;	/* use root group for this thread:	 * loop over all static fields of java.lang.ThreadGroup ...	 */	for (i=0; i<CLASS_NSFIELDS(ThreadGroupClass); i++)	{		Field* f = &CLASS_SFIELDS(ThreadGroupClass)[i];		/* ... and if it's a field called root, take it */		if (!strcmp (f->name->data, "root"))		{			unhand(tid)->group = * (jref *)FIELD_ADDRESS(f);		}	}	/* finally complain if we did not find the field */	assert(unhand(tid)->group != NULL);	unhand(tid)->runnable = NULL;	unhand(tid)->vmThread = (Hjava_lang_VMThread *)	  execute_java_constructor(NULL, NULL,				   VMThreadClass, "(Ljava/lang/Thread;)V",				   tid);	/* set Java thread associated with main thread */	linkNativeAndJavaThread (KTHREAD(current)(), unhand(tid)->vmThread);        /*	 * set context class loader of primordial thread to app classloader	 * must not be done earlier, since getCurrentThread() won't work         * before the KTHREAD(createfirst) and the vmdata assignment.	 *	 * If we're creating the Thread instance of the main thread, this	 * will trigger the initialization process of the java part of the	 * runtime. One pitfall during initialization is that java.lang.System	 * has to be initialized before kaffe.lang.AppClassLoader. Therefore,	 * we cannot call AppClassLoader.getSingleton() here, since that would	 * cause System and AppClassLoader to be initialized in the wrong order.	 */	do_execute_java_class_method (&retval, "java/lang/ClassLoader",				      NULL,				      "getSystemClassLoader",				      "()Ljava/lang/ClassLoader;");        unhand(tid)->contextClassLoader = (struct Hjava_lang_ClassLoader *) retval.l;	/* Attach thread to threadGroup */	do_execute_java_method(NULL, unhand(tid)->group, "addThread", "(Ljava/lang/Thread;)V", NULL, 0, tid);	DBG(VMTHREAD, dprintf("attachFakedThreadInstance(%s)=%p done\n", nm, tid); );}/* * helper function to start gc thread */staticvoidstartSpecialThread(void *arg){	void (*func)(void *);	void **pointer_args = (void **)arg;	void *argument;	jthread_t calling_thread;	threadData *thread_data = THREAD_DATA();	int r;	KSEM(init)(&thread_data->sem);	/* We save the value before the lock so we are sure	 * pointer_args is still a valid pointer on the stack.	 */	func = (void(*)(void*))pointer_args[0];	argument = pointer_args[1];	calling_thread = (jthread_t) pointer_args[2];	/* Thread started and arguments retrieved. */	KSEM(put)(&KTHREAD(get_data)(calling_thread)->sem);	/* We have now to wait the parent to synchronize the data	 * and link the thread to the Java VM.	 */	do {	  r = KSEM(get)(&thread_data->sem, (jlong)0);	} while (!r);	thread_data->exceptObj = NULL;	func(argument);}/* * Start a daemon thread, such as a gc or finalizer thread. * We give these threads a java incarnation for consistency. * It might not be strictly necessary for the gc thread. * * This guy can fail because of allocation failure, or because * createThread failed. * XXX */Hjava_lang_Thread*createDaemon(void* func, const char* nm, void *arg, int prio,	     size_t stacksize, struct _errorInfo *einfo){  Hjava_lang_Thread* tid;  Hjava_lang_VMThread *vmtid;  jthread_t nativeTid;  Hjava_lang_String* name;  void *specialArgument[3];  jvalue retval;  int r;DBG(VMTHREAD,	dprintf("createDaemon %s\n", nm);	);    /* Keep daemon threads as root objects */  vmtid = (Hjava_lang_VMThread*)newObject(VMThreadClass);  assert(vmtid != NULL);    name = stringC2Java(nm);  if (!name) {    postOutOfMemory(einfo);    return NULL;  }  tid = (Hjava_lang_Thread *)    execute_java_constructor(NULL, NULL,			     ThreadClass, "(Ljava/lang/VMThread;Ljava/lang/String;IZ)V",

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?