From b198e6651753955b049ecf361887ded86a841cea Mon Sep 17 00:00:00 2001 From: Christian Thalinger Date: Mon, 31 Mar 2008 17:31:53 +0200 Subject: [PATCH] Fixes PR59. * src/native/jni.c (_Jv_JNI_Get##name##Field): Added TRACEJNICALLS. (_Jv_JNI_Set##name##Field): Likewise. (_Jv_JNI_CallStaticObjectMethod): Likewise. (_Jv_JNI_CallStaticObjectMethodV): Likewise. (_Jv_JNI_CallStaticObjectMethodA): Likewise. (_Jv_JNI_CallStaticVoidMethod): Likewise. (_Jv_JNI_CallStaticVoidMethodV): Likewise. (_Jv_JNI_CallStaticVoidMethodA): Likewise. (_Jv_JNI_GetArrayLength): Likewise. (_Jv_JNI_Get##name##ArrayElements): Likewise. (_Jv_JNI_Get##name##ArrayRegion): Likewise. (jni_attach_current_thread): Check correctly if current thread is already attached. (_Jv_JNI_DetachCurrentThread): Check if current thread is already detached. * src/threads/posix/threads.c (threads_detach_thread): Likewise. * src/threads/threads-common.c (threads_init) [WITH_CLASSPATH_SUN]: Resolve correct thread init method. (thread_create_object): New function, but not yet implemented. (thread_create_initial_thread): Lot of changes. * src/threads/threads-common.h (thread_is_attached): New function. (thread_current_is_attached): Likewise. * src/vm/global.h (STR): New macro, stolen from OpenJDK. * src/vm/vm.c (vm_run): Detach the main thread before calling vm_destroy. (vm_destroy): Attach the main thread again as DestroyJavaVM thread. --- src/native/jni.c | 80 +++++++++++++------ src/threads/posix/threads.c | 9 +++ src/threads/threads-common.c | 151 +++++++++++++++++++++++------------ src/threads/threads-common.h | 44 ++++++++++ src/vm/global.h | 7 ++ src/vm/vm.c | 32 ++++++-- 6 files changed, 244 insertions(+), 79 deletions(-) diff --git a/src/native/jni.c b/src/native/jni.c index 74b04dd35..e2b947d19 100644 --- a/src/native/jni.c +++ b/src/native/jni.c @@ -2158,7 +2158,7 @@ type _Jv_JNI_Get##name##Field(JNIEnv *env, jobject obj, jfieldID fieldID) \ { \ intern ret; \ \ - STATISTICS(jniinvokation()); \ + TRACEJNICALLS(("_Jv_JNI_Get" STR(name) "Field(env=%p, obj=%p, fieldId=%p)", env, obj, fieldID)); \ \ LLNI_CRITICAL_START; \ \ @@ -2210,7 +2210,7 @@ jobject _Jv_JNI_GetObjectField(JNIEnv *env, jobject obj, jfieldID fieldID) void _Jv_JNI_Set##name##Field(JNIEnv *env, jobject obj, jfieldID fieldID, \ type value) \ { \ - STATISTICS(jniinvokation()); \ + TRACEJNICALLS(("_Jv_JNI_Set" STR(name) "Field(env=%p, obj=%p, fieldId=%p, value=%p)", env, obj, fieldID, value)); \ \ LLNI_CRITICAL_START; \ \ @@ -2372,6 +2372,8 @@ jobject _Jv_JNI_CallStaticObjectMethod(JNIEnv *env, jclass clazz, java_handle_t *o; va_list ap; + TRACEJNICALLS(("_Jv_JNI_CallStaticObjectMethod(env=%p, clazz=%p, methodID=%p, ...)", env, clazz, methodID)); + m = (methodinfo *) methodID; va_start(ap, methodID); @@ -2388,6 +2390,8 @@ jobject _Jv_JNI_CallStaticObjectMethodV(JNIEnv *env, jclass clazz, methodinfo *m; java_handle_t *o; + TRACEJNICALLS(("_Jv_JNI_CallStaticObjectMethodV(env=%p, clazz=%p, methodID=%p, args=%p)", env, clazz, methodID, args)); + m = (methodinfo *) methodID; o = _Jv_jni_CallObjectMethod(NULL, NULL, m, args); @@ -2402,6 +2406,8 @@ jobject _Jv_JNI_CallStaticObjectMethodA(JNIEnv *env, jclass clazz, methodinfo *m; java_handle_t *o; + TRACEJNICALLS(("_Jv_JNI_CallStaticObjectMethodA(env=%p, clazz=%p, methodID=%p, args=%p)", env, clazz, methodID, args)); + m = (methodinfo *) methodID; o = _Jv_jni_CallObjectMethodA(NULL, NULL, m, args); @@ -2416,6 +2422,8 @@ void _Jv_JNI_CallStaticVoidMethod(JNIEnv *env, jclass clazz, methodinfo *m; va_list ap; + TRACEJNICALLS(("_Jv_JNI_CallStaticVoidMethod(env=%p, clazz=%p, methodID=%p, ...)", env, clazz, methodID)); + m = (methodinfo *) methodID; va_start(ap, methodID); @@ -2429,6 +2437,8 @@ void _Jv_JNI_CallStaticVoidMethodV(JNIEnv *env, jclass clazz, { methodinfo *m; + TRACEJNICALLS(("_Jv_JNI_CallStaticVoidMethodV(env=%p, clazz=%p, methodID=%p, args=%p)", env, clazz, methodID, args)); + m = (methodinfo *) methodID; _Jv_jni_CallVoidMethod(NULL, NULL, m, args); @@ -2440,6 +2450,8 @@ void _Jv_JNI_CallStaticVoidMethodA(JNIEnv *env, jclass clazz, { methodinfo *m; + TRACEJNICALLS(("_Jv_JNI_CallStaticVoidMethodA(env=%p, clazz=%p, methodID=%p, args=%p)", env, clazz, methodID, args)); + m = (methodinfo *) methodID; _Jv_jni_CallVoidMethodA(NULL, NULL, m, args); @@ -2847,7 +2859,7 @@ jsize _Jv_JNI_GetArrayLength(JNIEnv *env, jarray array) java_handle_t *a; jsize size; - STATISTICS(jniinvokation()); + TRACEJNICALLS(("_Jv_JNI_GetArrayLength(env=%p, array=%p)", env, array)); a = (java_handle_t *) array; @@ -2982,7 +2994,7 @@ type *_Jv_JNI_Get##name##ArrayElements(JNIEnv *env, type##Array array, \ { \ java_handle_##intern##array_t *a; \ \ - STATISTICS(jniinvokation()); \ + TRACEJNICALLS(("_Jv_JNI_Get" STR(name) "ArrayElements(env=%p, array=%p, isCopy=%d)", env, array, isCopy)); \ \ a = (java_handle_##intern##array_t *) array; \ \ @@ -3062,7 +3074,7 @@ void _Jv_JNI_Get##name##ArrayRegion(JNIEnv *env, type##Array array, \ { \ java_handle_##intern##array_t *a; \ \ - STATISTICS(jniinvokation()); \ + TRACEJNICALLS(("_Jv_JNI_Get" STR(name) "ArrayRegion(env=%p, array=%p, start=%d, len=%d, buf=%p)", env, array, start, len, buf)); \ \ a = (java_handle_##intern##array_t *) array; \ \ @@ -3830,26 +3842,36 @@ jint _Jv_JNI_DestroyJavaVM(JavaVM *vm) *******************************************************************************/ -static s4 jni_attach_current_thread(void **p_env, void *thr_args, bool isdaemon) +static int jni_attach_current_thread(void **p_env, void *thr_args, bool isdaemon) { +#if defined(ENABLE_THREADS) JavaVMAttachArgs *vm_aargs; + bool result; -#if defined(ENABLE_THREADS) - if (thread_get_current() == NULL) { - vm_aargs = (JavaVMAttachArgs *) thr_args; + /* If the current thread has already been attached, this operation + is a no-op. */ - if (vm_aargs != NULL) { - if ((vm_aargs->version != JNI_VERSION_1_2) && - (vm_aargs->version != JNI_VERSION_1_4)) - return JNI_EVERSION; - } + result = thread_current_is_attached(); - if (!threads_attach_current_thread(vm_aargs, false)) - return JNI_ERR; + if (result == true) { + *p_env = _Jv_env; - if (!localref_table_init()) - return JNI_ERR; + return JNI_OK; } + + vm_aargs = (JavaVMAttachArgs *) thr_args; + + if (vm_aargs != NULL) { + if ((vm_aargs->version != JNI_VERSION_1_2) && + (vm_aargs->version != JNI_VERSION_1_4)) + return JNI_EVERSION; + } + + if (!threads_attach_current_thread(vm_aargs, false)) + return JNI_ERR; + + if (!localref_table_init()) + return JNI_ERR; #endif *p_env = _Jv_env; @@ -3893,14 +3915,24 @@ jint _Jv_JNI_AttachCurrentThread(JavaVM *vm, void **p_env, void *thr_args) jint _Jv_JNI_DetachCurrentThread(JavaVM *vm) { #if defined(ENABLE_THREADS) - threadobject *thread; + threadobject *t; + bool result; - STATISTICS(jniinvokation()); + TRACEJNICALLS(("_Jv_JNI_DetachCurrentThread(vm=%p)", vm)); - thread = thread_get_current(); + t = thread_get_current(); - if (thread == NULL) - return JNI_ERR; + /* Sanity check. */ + + assert(t != NULL); + + /* If the given thread has already been detached, this operation + is a no-op. */ + + result = thread_is_attached(t); + + if (result == false) + return true; /* We need to pop all frames before we can destroy the table. */ @@ -3909,7 +3941,7 @@ jint _Jv_JNI_DetachCurrentThread(JavaVM *vm) if (!localref_table_destroy()) return JNI_ERR; - if (!threads_detach_thread(thread)) + if (!threads_detach_thread(t)) return JNI_ERR; #endif diff --git a/src/threads/posix/threads.c b/src/threads/posix/threads.c index 351aa1119..17708a7bd 100644 --- a/src/threads/posix/threads.c +++ b/src/threads/posix/threads.c @@ -1284,6 +1284,7 @@ void threads_set_thread_priority(pthread_t tid, int priority) bool threads_detach_thread(threadobject *t) { + bool result; java_lang_Thread *object; java_handle_t *o; #if defined(ENABLE_JAVASE) @@ -1294,6 +1295,14 @@ bool threads_detach_thread(threadobject *t) methodinfo *m; #endif + /* If the given thread has already been detached, this operation + is a no-op. */ + + result = thread_is_attached(t); + + if (result == false) + return true; + DEBUGTHREADS("detaching", t); object = (java_lang_Thread *) threads_thread_get_object(t); diff --git a/src/threads/threads-common.c b/src/threads/threads-common.c index 4c6fb72ca..6637f0e56 100644 --- a/src/threads/threads-common.c +++ b/src/threads/threads-common.c @@ -178,26 +178,32 @@ void threads_init(void) /* Cache the java.lang.Thread initialization method. */ #if defined(WITH_CLASSPATH_GNU) + thread_method_init = class_resolveclassmethod(class_java_lang_Thread, utf_init, utf_new_char("(Ljava/lang/VMThread;Ljava/lang/String;IZ)V"), class_java_lang_Thread, true); + #elif defined(WITH_CLASSPATH_SUN) + thread_method_init = class_resolveclassmethod(class_java_lang_Thread, utf_init, - utf_java_lang_String__void, + utf_new_char("(Ljava/lang/ThreadGroup;Ljava/lang/String;)V"), class_java_lang_Thread, true); + #elif defined(WITH_CLASSPATH_CLDC1_1) + thread_method_init = class_resolveclassmethod(class_java_lang_Thread, utf_init, utf_java_lang_String__void, class_java_lang_Thread, true); + #else # error unknown classpath configuration #endif @@ -209,6 +215,16 @@ void threads_init(void) } +/* thread_create_object ******************************************************** + +*******************************************************************************/ + +static void thread_create_object(void) +{ +#warning refactor thread_create_initial_thread and threads_attach_current_thread, maybe threads_thread_start_internal +} + + /* thread_create_initial_threadgroups ****************************************** Create the initial threadgroups. @@ -379,19 +395,18 @@ static void thread_create_initial_thread(void) #elif defined(WITH_CLASSPATH_SUN) - /* Set the thread group and the priority. java.lang.Thread. - requires it because it sets the priority of the current thread - to the parent's one (which is the current thread in this - case). */ + /* Set the priority. java.lang.Thread. requires it because + it sets the priority of the current thread to the parent's one + (which is the current thread in this case). */ - LLNI_field_set_ref(to, group, threadgroup_main); LLNI_field_set_val(to, priority, NORM_PRIORITY); - /* Call: java.lang.Thread.(Ljava/lang/String;)V */ + /* Call: + java.lang.Thread.(Ljava/lang/ThreadGroup;Ljava/lang/String;)V */ o = (java_object_t *) to; - (void) vm_call_method(thread_method_init, o, name); + (void) vm_call_method(thread_method_init, o, threadgroup_main, name); if (exceptions_get_exception()) vm_abort("threads_init: exception while initializing main thread"); @@ -539,10 +554,12 @@ void threads_thread_free(threadobject *t) threadlist_index_add(t->index); - /* Add the thread data structure to the free list. */ + /* Set the reference to the Java object to NULL. */ threads_thread_set_object(t, NULL); + /* Add the thread data structure to the free list. */ + threadlist_free_add(t); /* Unlock the thread lists. */ @@ -743,40 +760,47 @@ void threads_thread_start(java_handle_t *object) bool threads_attach_current_thread(JavaVMAttachArgs *vm_aargs, bool isdaemon) { - threadobject *thread; + bool result; + threadobject *t; utf *u; java_handle_t *s; java_handle_t *o; - java_lang_Thread *t; + java_lang_Thread *to; #if defined(ENABLE_JAVASE) java_lang_ThreadGroup *group; - threadobject *mainthread; - java_lang_Thread *mainthreado; - classinfo *c; - methodinfo *m; #endif #if defined(WITH_CLASSPATH_GNU) java_lang_VMThread *vmt; + classinfo *c; + methodinfo *m; #endif + /* If the current thread has already been attached, this operation + is a no-op. */ + + result = thread_current_is_attached(); + + if (result == true) + return true; + /* Enter the join-mutex, so if the main-thread is currently waiting to join all threads, the number of non-daemon threads is correct. */ threads_mutex_join_lock(); - /* create internal thread data-structure */ + /* Create internal thread data structure. */ - thread = threads_thread_new(); + t = threads_thread_new(); - /* thread is a Java thread and running */ + /* Thread is a Java thread and running. */ - thread->flags = THREAD_FLAG_JAVA; + t->flags = THREAD_FLAG_JAVA; if (isdaemon) - thread->flags |= THREAD_FLAG_DAEMON; + t->flags |= THREAD_FLAG_DAEMON; /* The thread is flagged and (non-)daemon thread, we can leave the mutex. */ @@ -785,19 +809,19 @@ bool threads_attach_current_thread(JavaVMAttachArgs *vm_aargs, bool isdaemon) /* create a java.lang.Thread object */ - t = (java_lang_Thread *) builtin_new(class_java_lang_Thread); + to = (java_lang_Thread *) builtin_new(class_java_lang_Thread); /* XXX memory leak!!! */ - if (t == NULL) + if (to == NULL) return false; - threads_thread_set_object(thread, (java_handle_t *) t); + threads_thread_set_object(t, (java_handle_t *) to); - /* thread is completely initialized */ + /* Thread is completely initialized. */ - threads_thread_state_runnable(thread); + threads_thread_state_runnable(t); - DEBUGTHREADS("attaching", thread); + DEBUGTHREADS("attaching", t); #if defined(ENABLE_INTRP) /* create interpreter stack */ @@ -820,62 +844,63 @@ bool threads_attach_current_thread(JavaVMAttachArgs *vm_aargs, bool isdaemon) /* set the thread */ - LLNI_field_set_ref(vmt, thread, t); - LLNI_field_set_val(vmt, vmdata, (java_lang_Object *) thread); + LLNI_field_set_ref(vmt, thread, to); + LLNI_field_set_val(vmt, vmdata, (java_lang_Object *) t); #elif defined(WITH_CLASSPATH_SUN) - vm_abort("threads_attach_current_thread: IMPLEMENT ME!"); + /* Sun's java.lang.Thread does not have a VMThread field in the + class. Nothing to do here. */ #elif defined(WITH_CLASSPATH_CLDC1_1) - LLNI_field_set_val(t, vm_thread, (java_lang_Object *) thread); + LLNI_field_set_val(to, vm_thread, (java_lang_Object *) t); #else # error unknown classpath configuration #endif + /* Get the thread name. */ + if (vm_aargs != NULL) { - u = utf_new_char(vm_aargs->name); -#if defined(ENABLE_JAVASE) - group = (java_lang_ThreadGroup *) vm_aargs->group; -#endif + u = utf_new_char(vm_aargs->name); } else { - u = utf_null; + u = utf_null; + } + #if defined(ENABLE_JAVASE) - /* get the main thread */ + /* Get the threadgroup. If no threadgroup was given, use the main + threadgroup. */ - mainthread = threadlist_first(); - mainthreado = (java_lang_Thread *) threads_thread_get_object(mainthread); - LLNI_field_get_ref(mainthreado, group, group); + if (vm_aargs != NULL) + group = (java_lang_ThreadGroup *) vm_aargs->group; + + if (group == NULL) + group = threadgroup_main; #endif - } - /* the the thread name */ + /* The thread name. */ s = javastring_new(u); /* for convenience */ - o = (java_handle_t *) t; + o = (java_handle_t *) to; #if defined(WITH_CLASSPATH_GNU) + (void) vm_call_method(thread_method_init, o, vmt, s, NORM_PRIORITY, isdaemon); -#elif defined(WITH_CLASSPATH_CLDC1_1) - (void) vm_call_method(thread_method_init, o, s); -#endif if (exceptions_get_exception()) return false; -#if defined(ENABLE_JAVASE) - /* store the thread group in the object */ + /* Store the threadgroup in the Java object. */ - LLNI_field_set_ref(t, group, group); + LLNI_field_set_ref(to, group, group); - /* add thread to given thread-group */ + /* Add thread to given threadgroup. */ LLNI_class_get(group, c); @@ -885,12 +910,38 @@ bool threads_attach_current_thread(JavaVMAttachArgs *vm_aargs, bool isdaemon) class_java_lang_ThreadGroup, true); + if (m == NULL) + return false; + o = (java_handle_t *) group; - (void) vm_call_method(m, o, t); + (void) vm_call_method(m, o, to); + + if (exceptions_get_exception()) + return false; + +#elif defined(WITH_CLASSPATH_SUN) + + /* Set the priority. java.lang.Thread. requires it because + it sets the priority of the current thread to the parent's one + (which is the current thread in this case). */ + + LLNI_field_set_val(to, priority, NORM_PRIORITY); + + (void) vm_call_method(thread_method_init, o, group, s); + + if (exceptions_get_exception()) + return false; + +#elif defined(WITH_CLASSPATH_CLDC1_1) + + (void) vm_call_method(thread_method_init, o, s); if (exceptions_get_exception()) return false; + +#else +# error unknown classpath configuration #endif return true; diff --git a/src/threads/threads-common.h b/src/threads/threads-common.h index 8823ecb1a..a0dc51a80 100644 --- a/src/threads/threads-common.h +++ b/src/threads/threads-common.h @@ -137,6 +137,50 @@ inline static java_handle_t *threads_get_current_object(void) return o; } +/* thread_is_attached ********************************************************** + + Returns if the given thread is attached to the VM. + + RETURN: + true .... the thread is attached to the VM + false ... the thread is not + +*******************************************************************************/ + +inline static bool thread_is_attached(threadobject *t) +{ + java_handle_t *o; + + o = threads_thread_get_object(t); + + if (o != NULL) + return true; + else + return false; +} + + +/* thread_current_is_attached ************************************************** + + Returns if the current thread is attached to the VM. + + RETURN: + true .... the thread is attached to the VM + false ... the thread is not + +*******************************************************************************/ + +inline static bool thread_current_is_attached(void) +{ + threadobject *t; + bool result; + + t = THREADOBJECT; + result = thread_is_attached(t); + + return result; +} + /* function prototypes ********************************************************/ diff --git a/src/vm/global.h b/src/vm/global.h index 7445b750d..c0fe462a2 100644 --- a/src/vm/global.h +++ b/src/vm/global.h @@ -88,6 +88,13 @@ typedef union { #endif +/* convenience macros *********************************************************/ + +/* Makes a string of the argument (which is not macro-expanded). */ + +#define STR(a) #a + + /* forward typedefs ***********************************************************/ typedef struct java_object_t java_object_t; diff --git a/src/vm/vm.c b/src/vm/vm.c index 83e06f26d..c9f884e7b 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -1660,7 +1660,8 @@ void vm_run(JavaVM *vm, JavaVMInitArgs *vm_args) s4 oalength; utf *u; java_handle_t *s; - s4 status; + int status; + threadobject *t; s4 i; #if !defined(NDEBUG) @@ -1787,11 +1788,19 @@ void vm_run(JavaVM *vm, JavaVMInitArgs *vm_args) status = 1; } - /* unload the JavaVM */ + /* Detach the main thread so that it appears to have ended when + the application's main method exits. */ + + t = thread_get_current(); + + if (!threads_detach_thread(t)) + vm_abort("vm_run: Could not detach main thread."); + + /* Destroy the JavaVM. */ (void) vm_destroy(vm); - /* and exit */ + /* And exit. */ vm_exit(status); } @@ -1803,9 +1812,22 @@ void vm_run(JavaVM *vm, JavaVMInitArgs *vm_args) *******************************************************************************/ -s4 vm_destroy(JavaVM *vm) +int vm_destroy(JavaVM *vm) { #if defined(ENABLE_THREADS) + /* Create a a trivial new Java waiter thread called + "DestroyJavaVM". */ + + JavaVMAttachArgs args; + + args.name = "DestroyJavaVM"; + args.group = NULL; + + if (!threads_attach_current_thread(&args, false)) + return 1; + + /* Wait until we are the last non-daemon thread. */ + threads_join_all_threads(); #endif @@ -1813,7 +1835,7 @@ s4 vm_destroy(JavaVM *vm) vm_created = false; - /* everything's ok */ + /* Everything is ok. */ return 0; } -- 2.25.1