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 + -
显示快捷键?