From 7c185af99e9a0e34ef4e716a8ffb1bfce5aa70c0 Mon Sep 17 00:00:00 2001 From: Gust Date: Tue, 24 Dec 2024 00:48:36 +0800 Subject: [PATCH] fix thread interrupted, fix threadgroup, fix zip path with utf-8 --- minijvm/c/jvm/global.c | 2 + minijvm/c/jvm/interpreter.c | 9 ++- minijvm/c/jvm/jit.c | 2 +- minijvm/c/jvm/jni_io.c | 73 ++----------------- minijvm/c/jvm/jni_std.c | 24 ++++-- minijvm/c/jvm/jvm.c | 8 +- minijvm/c/jvm/jvm.h | 7 +- minijvm/c/jvm/jvm_util.c | 27 +++++-- minijvm/c/jvm/jvm_util.h | 4 + .../java/java/lang/StackTraceElement.java | 5 +- .../java/src/main/java/java/lang/Thread.java | 62 ++++++++++++++-- .../src/main/java/java/lang/ThreadGroup.java | 4 - .../src/main/java/org/mini/vm/VmUtil.java | 49 ++++++++++++- 13 files changed, 178 insertions(+), 98 deletions(-) diff --git a/minijvm/c/jvm/global.c b/minijvm/c/jvm/global.c index bab934ce..47c487ef 100644 --- a/minijvm/c/jvm/global.c +++ b/minijvm/c/jvm/global.c @@ -44,6 +44,7 @@ c8 *STRS_CLASS_EXCEPTION[] = { "java.lang.ClassCastException", "java.lang.ArrayIndexOutOfBoundsException", "java.lang.InstantiationException", + "java.lang.InterruptedException", }; c8 const *STR_CLASS_JAVA_LANG_BOOLEAN = "java/lang/Boolean"; @@ -58,6 +59,7 @@ c8 const *STR_CLASS_JAVA_LANG_STRING = "java/lang/String"; c8 const *STR_CLASS_JAVA_LANG_STRINGBUILDER = "java/lang/StringBuilder"; c8 const *STR_CLASS_JAVA_LANG_OBJECT = "java/lang/Object"; c8 const *STR_CLASS_JAVA_LANG_THREAD = "java/lang/Thread"; +c8 const *STR_CLASS_JAVA_LANG_INTERRUPTEDEXCEPTION = "java/lang/InterruptedException"; c8 const *STR_CLASS_JAVA_LANG_CLASS = "java/lang/Class"; c8 const *STR_CLASS_JAVA_LANG_CLASSLOADER = "java/lang/ClassLoader"; c8 const *STR_CLASS_JAVA_LANG_REF_REFERENCE = "java/lang/ref/Reference"; diff --git a/minijvm/c/jvm/interpreter.c b/minijvm/c/jvm/interpreter.c index 37fcc1bc..a9d40a5b 100755 --- a/minijvm/c/jvm/interpreter.c +++ b/minijvm/c/jvm/interpreter.c @@ -130,9 +130,6 @@ static s32 filterClassName(Utf8String *clsName) { if (offset < 0 && thrd_info->suspend_count) {\ runtime->pc = ip;\ runtime->stack->sp = sp;\ - if (thrd_info->is_interrupt) {\ - goto label_exit_while;\ - }\ check_suspend_and_pause(runtime);\ }\ } @@ -601,6 +598,10 @@ s32 execute_method_impl(MethodInfo *method, Runtime *pruntime) { if (method->is_sync)_synchronized_lock_method(method, runtime); + if (runtime->thrd_info->is_stop) {//if stop=1 then exit thread + goto label_exit_while; + } + if (JIT_ENABLE && ca->jit.state == JIT_GEN_SUCCESS) { //jvm_printf("jit call %s.%s()\n", method->_this_class->name->data, method->name->data); ret = ca->jit.func(method, runtime); @@ -3011,7 +3012,7 @@ s32 execute_method_impl(MethodInfo *method, Runtime *pruntime) { if (fi->isrefer) {// garbage collection flag *ip = op_putfield_ref; } else { - // non-reference type + // non-reference type switch (fi->datatype_bytes) { case 4: { *ip = op_putfield_int; diff --git a/minijvm/c/jvm/jit.c b/minijvm/c/jvm/jit.c index 636eed41..9c6ad825 100644 --- a/minijvm/c/jvm/jit.c +++ b/minijvm/c/jvm/jit.c @@ -1158,7 +1158,7 @@ void gen_jit_suspend_check_func() { { sljit_emit_op1(C, SLJIT_MOV_P, SLJIT_MEM1(SLJIT_SP), sizeof(sljit_sw) * LOCAL_R2, SLJIT_R2, 0); _gen_save_sp_ip(C); - sljit_emit_op1(C, SLJIT_MOV_U8, SLJIT_R1, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(JavaThreadInfo, is_interrupt)); + sljit_emit_op1(C, SLJIT_MOV_U8, SLJIT_R1, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(JavaThreadInfo, is_stop)); jump_to_interrupted = sljit_emit_cmp(C, SLJIT_NOT_EQUAL, SLJIT_R1, 0, SLJIT_IMM, 0); { jump_not_interrupted = sljit_emit_jump(C, SLJIT_JUMP); diff --git a/minijvm/c/jvm/jni_io.c b/minijvm/c/jvm/jni_io.c index 1d108ce4..063ee993 100644 --- a/minijvm/c/jvm/jni_io.c +++ b/minijvm/c/jvm/jni_io.c @@ -1465,19 +1465,9 @@ s32 org_mini_zip_ZipFile_getEntryIndex0(Runtime *runtime, JClass *clazz) { Instance *name_arr = localvar_getRefer(runtime->localvar, 1); s32 ret = -1; if (zip_path_arr && name_arr) { - Utf8String *filepath = utf8_create_c(zip_path_arr->arr_body); - ByteBuf *zip_path = bytebuf_create(0); - conv_utf8_2_platform_encoding(zip_path, filepath); - utf8_clear(filepath); - utf8_append_c(filepath, name_arr->arr_body); - ByteBuf *name = bytebuf_create(0); - //conv_utf8_2_platform_encoding(name, filepath); - ret = zip_get_file_index(zip_path->buf, utf8_cstr(filepath)); + ret = zip_get_file_index(zip_path_arr->arr_body, name_arr->arr_body); - bytebuf_destory(zip_path); - bytebuf_destory(name); - utf8_destory(filepath); } push_int(runtime->stack, ret); #if _JVM_DEBUG_LOG_LEVEL > 5 @@ -1492,19 +1482,9 @@ s32 org_mini_zip_ZipFile_getEntrySize0(Runtime *runtime, JClass *clazz) { Instance *name_arr = localvar_getRefer(runtime->localvar, 1); s64 ret = -1; if (zip_path_arr && name_arr) { - Utf8String *filepath = utf8_create_c(zip_path_arr->arr_body); - ByteBuf *zip_path = bytebuf_create(0); - conv_utf8_2_platform_encoding(zip_path, filepath); - utf8_clear(filepath); - utf8_append_c(filepath, name_arr->arr_body); - ByteBuf *name = bytebuf_create(0); - //conv_utf8_2_platform_encoding(name, filepath); - ret = zip_get_file_unzip_size(zip_path->buf, utf8_cstr(filepath)); + ret = zip_get_file_unzip_size(zip_path_arr->arr_body, name_arr->arr_body); - bytebuf_destory(zip_path); - bytebuf_destory(name); - utf8_destory(filepath); } push_long(runtime->stack, ret); #if _JVM_DEBUG_LOG_LEVEL > 5 @@ -1519,26 +1499,14 @@ s32 org_mini_zip_ZipFile_getEntry0(Runtime *runtime, JClass *clazz) { Instance *name_arr = localvar_getRefer(runtime->localvar, 1); s32 ret = -1; if (zip_path_arr && name_arr) { - Utf8String *filepath = utf8_create_c(zip_path_arr->arr_body); - ByteBuf *zip_path = bytebuf_create(0); - conv_utf8_2_platform_encoding(zip_path, filepath); - utf8_clear(filepath); - utf8_append_c(filepath, name_arr->arr_body); - ByteBuf *name = bytebuf_create(0); - //conv_utf8_2_platform_encoding(name, filepath); - - s64 filesize = zip_get_file_unzip_size(zip_path->buf, utf8_cstr(filepath)); + s64 filesize = zip_get_file_unzip_size(zip_path_arr->arr_body, name_arr->arr_body); if (filesize >= 0) { Instance *arr = jarray_create_by_type_index(runtime, (s32) filesize, DATATYPE_BYTE); - ret = zip_loadfile_to_mem(zip_path->buf, utf8_cstr(filepath), arr->arr_body, filesize); + ret = zip_loadfile_to_mem(zip_path_arr->arr_body, name_arr->arr_body, arr->arr_body, filesize); if (ret == 0) { push_ref(runtime->stack, arr); } } - - bytebuf_destory(zip_path); - bytebuf_destory(name); - utf8_destory(filepath); } if (ret) { push_ref(runtime->stack, NULL); @@ -1556,20 +1524,10 @@ s32 org_mini_zip_ZipFile_putEntry0(Runtime *runtime, JClass *clazz) { Instance *content_arr = localvar_getRefer(runtime->localvar, 2); s32 ret = -1; if (zip_path_arr && name_arr) { - Utf8String *filepath = utf8_create_c(zip_path_arr->arr_body); - ByteBuf *zip_path = bytebuf_create(0); - conv_utf8_2_platform_encoding(zip_path, filepath); - utf8_clear(filepath); - utf8_append_c(filepath, name_arr->arr_body); - ByteBuf *name = bytebuf_create(0); - //conv_utf8_2_platform_encoding(name, filepath); - zip_savefile_mem(zip_path->buf, utf8_cstr(filepath), content_arr ? content_arr->arr_body : NULL, content_arr ? content_arr->arr_length : 0); + zip_savefile_mem(zip_path_arr->arr_body, name_arr->arr_body, content_arr ? content_arr->arr_body : NULL, content_arr ? content_arr->arr_length : 0); ret = 0; - bytebuf_destory(zip_path); - bytebuf_destory(name); - utf8_destory(filepath); } push_int(runtime->stack, ret); #if _JVM_DEBUG_LOG_LEVEL > 5 @@ -1584,14 +1542,9 @@ s32 org_mini_zip_ZipFile_fileCount0(Runtime *runtime, JClass *clazz) { s32 ret = 0; if (zip_path_arr) { - Utf8String *filepath = utf8_create_c(zip_path_arr->arr_body); - ByteBuf *zip_path = bytebuf_create(0); - conv_utf8_2_platform_encoding(zip_path, filepath); - ret = zip_filecount(zip_path->buf); + ret = zip_filecount(zip_path_arr->arr_body); - bytebuf_destory(zip_path); - utf8_destory(filepath); } push_int(runtime->stack, ret); #if _JVM_DEBUG_LOG_LEVEL > 5 @@ -1605,11 +1558,8 @@ s32 org_mini_zip_ZipFile_listFiles0(Runtime *runtime, JClass *clazz) { Instance *zip_path_arr = localvar_getRefer(runtime->localvar, 0); s32 ret = -1; if (zip_path_arr) { - Utf8String *filepath = utf8_create_c(zip_path_arr->arr_body); - ByteBuf *zip_path = bytebuf_create(0); - conv_utf8_2_platform_encoding(zip_path, filepath); - ArrayList *list = zip_get_filenames(zip_path->buf); + ArrayList *list = zip_get_filenames(zip_path_arr->arr_body); if (list) { Utf8String *clustr = utf8_create_c(STR_CLASS_JAVA_LANG_STRING); Instance *jarr = jarray_create_by_type_name(runtime, list->length, clustr, NULL); @@ -1627,8 +1577,6 @@ s32 org_mini_zip_ZipFile_listFiles0(Runtime *runtime, JClass *clazz) { ret = 0; } - bytebuf_destory(zip_path); - utf8_destory(filepath); } if (ret == -1) { push_ref(runtime->stack, NULL); @@ -1645,14 +1593,9 @@ s32 org_mini_zip_ZipFile_isDirectory0(Runtime *runtime, JClass *clazz) { s32 index = localvar_getInt(runtime->localvar, 1); s32 ret = -1; if (zip_path_arr) { - Utf8String *filepath = utf8_create_c(zip_path_arr->arr_body); - ByteBuf *zip_path = bytebuf_create(0); - conv_utf8_2_platform_encoding(zip_path, filepath); - ret = zip_is_directory(zip_path->buf, index); + ret = zip_is_directory(zip_path_arr->arr_body, index); - bytebuf_destory(zip_path); - utf8_destory(filepath); } push_int(runtime->stack, ret); diff --git a/minijvm/c/jvm/jni_std.c b/minijvm/c/jvm/jni_std.c index 18bd324e..1c9b584d 100644 --- a/minijvm/c/jvm/jni_std.c +++ b/minijvm/c/jvm/jni_std.c @@ -628,8 +628,8 @@ s32 java_lang_Object_wait(Runtime *runtime, JClass *clazz) { invoke_deepth(runtime); jvm_printf("java_lang_Object_wait %llx wait %lld\n", (s64) (intptr_t) ins, l2d.l); #endif - jthread_waitTime(&ins->mb, runtime, l2d.l); - return 0; + s32 ret = jthread_waitTime(&ins->mb, runtime, l2d.l); + return ret; } s32 java_lang_Runtime_exitInternal(Runtime *runtime, JClass *clazz) { @@ -1206,8 +1206,8 @@ s32 java_lang_Thread_sleep(Runtime *runtime, JClass *clazz) { invoke_deepth(runtime); jvm_printf("java_lang_Thread_sleep %lld\n", l2d.l); #endif - jthread_sleep(runtime, l2d.l); - return 0; + s32 ret = jthread_sleep(runtime, l2d.l); + return ret; } s32 java_lang_Thread_start(Runtime *runtime, JClass *clazz) { @@ -1270,7 +1270,13 @@ s32 java_lang_Thread_interrupt0(Runtime *runtime, JClass *clazz) { Instance *ins = (Instance *) localvar_getRefer(runtime->localvar, 0); Runtime *rt_thread = jthread_get_stackframe_value(runtime->jvm, ins); - rt_thread->thrd_info->is_interrupt = 1; + if (rt_thread) { + rt_thread->thrd_info->is_interrupt = 1; + + if (rt_thread->thrd_info->thread_status == THREAD_STATUS_WAIT) { + jthread_wakeup(rt_thread); + } + } #if _JVM_DEBUG_LOG_LEVEL > 5 invoke_deepth(runtime); jvm_printf("java_lang_Thread_interrupt0 \n"); @@ -1279,6 +1285,13 @@ s32 java_lang_Thread_interrupt0(Runtime *runtime, JClass *clazz) { return 0; } +s32 java_lang_Thread_interrupted(Runtime *runtime, JClass *clazz) { + + push_int(runtime->stack, runtime->thrd_info->is_interrupt != 0); + + return 0; +} + s32 java_lang_Thread_setContextClassLoader0(Runtime *runtime, JClass *clazz) { RuntimeStack *stack = runtime->stack; Instance *ins_thread = (Instance *) localvar_getRefer(runtime->localvar, 0); @@ -1538,6 +1551,7 @@ static java_native_method METHODS_STD_TABLE[] = { {"java/lang/Thread", "activeCount", "()I", java_lang_Thread_activeCount}, {"java/lang/Thread", "setPriority0", "(I)V", java_lang_Thread_setPriority0}, {"java/lang/Thread", "interrupt0", "()V", java_lang_Thread_interrupt0}, + {"java/lang/Thread", "interrupted", "()V", java_lang_Thread_interrupted}, {"java/lang/Thread", "setContextClassLoader0", "(Ljava/lang/ClassLoader;)V", java_lang_Thread_setContextClassLoader0}, {"java/lang/Thread", "getContextClassLoader0", "()Ljava/lang/ClassLoader;", java_lang_Thread_getContextClassLoader0}, {"java/lang/Throwable", "printStackTrace0", "", java_io_Throwable_printStackTrace0}, diff --git a/minijvm/c/jvm/jvm.c b/minijvm/c/jvm/jvm.c index a1fb4f03..414298ff 100644 --- a/minijvm/c/jvm/jvm.c +++ b/minijvm/c/jvm/jvm.c @@ -316,13 +316,19 @@ s32 jvm_init(MiniJVM *jvm, c8 *p_bootclasspath, c8 *p_classpath) { jvm_printf("[ERROR]maybe bootstrap classpath misstake: %s \n", p_bootclasspath); return -1; } + //load bootstrap class utf8_clear(clsName); utf8_append_c(clsName, STR_CLASS_JAVA_LANG_THREAD); classes_load_get(NULL, clsName, runtime); + utf8_clear(clsName); utf8_append_c(clsName, STR_CLASS_SUN_MISC_LAUNCHER); classes_load_get(NULL, clsName, runtime); - //开始装载类 + //for interrupted thread + utf8_clear(clsName); + utf8_append_c(clsName, STR_CLASS_JAVA_LANG_INTERRUPTEDEXCEPTION);//must load this class ,because it will be used when thread interrupt ,but it can not load when that thread is marked as interrupted + JClass *c2 = classes_load_get(NULL, clsName, runtime); + Instance *interruptedException = instance_create(runtime, c); utf8_destory(clsName); gc_move_objs_thread_2_gc(runtime); runtime_destory(runtime); diff --git a/minijvm/c/jvm/jvm.h b/minijvm/c/jvm/jvm.h index 44e4c2ca..a0642e82 100644 --- a/minijvm/c/jvm/jvm.h +++ b/minijvm/c/jvm/jvm.h @@ -27,7 +27,7 @@ extern "C" { //======================= micro define ============================= //_JVM_DEBUG 01=thread info, 02=garage&jit info , 03=class load, 04=method call, 06=all bytecode -#define _JVM_DEBUG_LOG_LEVEL 01 +#define _JVM_DEBUG_LOG_LEVEL 02 #define _JVM_DEBUG_LOG_TO_FILE 0 #define _JVM_DEBUG_GARBAGE_DUMP 0 #define _JVM_DEBUG_PROFILE 0 @@ -456,6 +456,7 @@ enum { JVM_EXCEPTION_CLASSCAST, JVM_EXCEPTION_ARRAYINDEXOUTOFBOUNDS, JVM_EXCEPTION_INSTANTIATION, + JVM_EXCEPTION_INTERRUPTED, }; enum { @@ -479,6 +480,7 @@ extern c8 const *STR_CLASS_JAVA_LANG_DOUBLE; extern c8 const *STR_CLASS_JAVA_LANG_FLOAT; extern c8 const *STR_CLASS_JAVA_LANG_OBJECT; extern c8 const *STR_CLASS_JAVA_LANG_THREAD; +extern c8 const *STR_CLASS_JAVA_LANG_INTERRUPTEDEXCEPTION; extern c8 const *STR_CLASS_JAVA_LANG_CLASS; extern c8 const *STR_CLASS_JAVA_LANG_CLASSLOADER; extern c8 const *STR_CLASS_JAVA_LANG_REF_REFERENCE; @@ -1263,7 +1265,8 @@ struct _JavaThreadInfo { u8 volatile is_suspend; u8 volatile is_unparked; u8 volatile is_blocking;// some of native method will enter blocking state - u8 is_interrupt; + u8 is_stop; //thread is marked as stop status, need set is_interrupt=1 also + u8 is_interrupt; //thread is marked as interrupt, set by Thread.interrupt(); u8 type;// gc /jdwp /normal thrd_t pthread; diff --git a/minijvm/c/jvm/jvm_util.c b/minijvm/c/jvm/jvm_util.c index 65d30b6e..cddc862a 100644 --- a/minijvm/c/jvm/jvm_util.c +++ b/minijvm/c/jvm/jvm_util.c @@ -309,7 +309,7 @@ void thread_stop_all(MiniJVM *jvm) { jthread_suspend(r); r->thrd_info->no_pause = 1; - r->thrd_info->is_interrupt = 1; + r->thrd_info->is_stop = 1; MemoryBlock *tl = r->thrd_info->curThreadLock; if (tl) { jthread_lock(tl, r); @@ -1100,12 +1100,20 @@ s32 jthread_waitTime(MemoryBlock *mb, Runtime *runtime, s64 waitms) { runtime->thrd_info->thread_status = thread_status; runtime->thrd_info->curThreadLock = NULL; jthread_block_exit(runtime); + return check_throw_interruptexception(runtime); +} + +//if the thread is waiting , wake it up +s32 jthread_wakeup(Runtime *runtime) { + MemoryBlock *tl = runtime->thrd_info->curThreadLock; + jthread_lock(tl, runtime); + jthread_notify(tl, runtime); + jthread_unlock(tl, runtime); return 0; } s32 jthread_sleep(Runtime *runtime, s64 ms) { static const s64 PERIOD = 500; - s32 ret = 0; jthread_block_enter(runtime); u8 thread_status = runtime->thrd_info->thread_status; runtime->thrd_info->thread_status = THREAD_STATUS_SLEEPING; @@ -1117,15 +1125,24 @@ s32 jthread_sleep(Runtime *runtime, s64 ms) { remain = ms - sleeped; threadSleep(remain < PERIOD ? remain : PERIOD); sleeped += PERIOD; - if (runtime->thrd_info->is_interrupt) { - ret = 1; + if (runtime->thrd_info->is_interrupt || runtime->thrd_info->is_stop) { break; } } } runtime->thrd_info->thread_status = thread_status; jthread_block_exit(runtime); - return ret; + return check_throw_interruptexception(runtime);; +} + +s32 check_throw_interruptexception(Runtime *runtime) { + if (!runtime->thrd_info->is_interrupt) { + return RUNTIME_STATUS_NORMAL; + } + runtime->thrd_info->is_interrupt = 0; + Instance *exception = exception_create(JVM_EXCEPTION_INTERRUPTED, runtime); + push_ref(runtime->stack, (__refer) exception); + return RUNTIME_STATUS_EXCEPTION; } s32 check_suspend_and_pause(Runtime *runtime) { diff --git a/minijvm/c/jvm/jvm_util.h b/minijvm/c/jvm/jvm_util.h index 49ded5b6..d81839aa 100644 --- a/minijvm/c/jvm/jvm_util.h +++ b/minijvm/c/jvm/jvm_util.h @@ -273,6 +273,8 @@ s32 jthread_notifyAll(MemoryBlock *mb, Runtime *runtime); s32 jthread_waitTime(MemoryBlock *mb, Runtime *runtime, s64 waitms); +s32 jthread_wakeup(Runtime *runtime); + s32 jthread_sleep(Runtime *runtime, s64 ms); s32 jthread_yield(Runtime *runtime); @@ -285,6 +287,8 @@ void jthread_block_exit(Runtime *runtime); void jthread_block_enter(Runtime *runtime); +s32 check_throw_interruptexception(Runtime *runtime); + s32 check_suspend_and_pause(Runtime *runtime); void thread_lock_dispose(ThreadLock *lock); diff --git a/minijvm/java/src/main/java/java/lang/StackTraceElement.java b/minijvm/java/src/main/java/java/lang/StackTraceElement.java index 9c4b88b5..af086ef2 100644 --- a/minijvm/java/src/main/java/java/lang/StackTraceElement.java +++ b/minijvm/java/src/main/java/java/lang/StackTraceElement.java @@ -5,11 +5,8 @@ */ package java.lang; -import java.util.logging.Level; -import java.util.logging.Logger; /** - * * @author gust */ public class StackTraceElement { @@ -30,7 +27,7 @@ Class getDeclaringClass() { } public String getClassName() { - return declaringClass; + return declaringClass.replace('/', '.'); } /** diff --git a/minijvm/java/src/main/java/java/lang/Thread.java b/minijvm/java/src/main/java/java/lang/Thread.java index 9e4ec14b..ea028e1a 100644 --- a/minijvm/java/src/main/java/java/lang/Thread.java +++ b/minijvm/java/src/main/java/java/lang/Thread.java @@ -26,6 +26,7 @@ package java.lang; +import org.mini.vm.RefNative; import org.mini.vm.ThreadCreateHandler; /** @@ -213,14 +214,20 @@ private void init(ThreadGroup group, Runnable target, String name) { Thread parent = currentThread(); if (group == null) { - this.group = parent.getThreadGroup(); - if (this.group == null) { + ThreadGroup pg = parent.getThreadGroup(); + if (pg == null) { ThreadGroup systemThreadGroup = new ThreadGroup(); parent.group = new ThreadGroup(systemThreadGroup, "main"); parent.group.add(parent); this.group = parent.group; + } else { + this.group = pg; } + } else { + this.group = group; } + this.group.add(this); + this.target = target; this.name = name.toCharArray(); this.priority = parent.getPriority(); @@ -268,6 +275,10 @@ public Thread(Runnable target) { init(target, "Thread-" + nextThreadNum()); } + public Thread(ThreadGroup group, Runnable target) { + init(group, target, "Thread-" + nextThreadNum()); + } + /** * Allocates a new Thread object with the given target and * name. @@ -324,9 +335,7 @@ public void interrupt() { } - static public boolean interrupted() { - return false; - } + static public native boolean interrupted(); /** * Tests if this thread is alive. A thread is alive if it has been started @@ -575,7 +584,50 @@ private void dispatchUncaughtException(Throwable e) { } + private static void checkCaller() { + Throwable throwable = new Throwable(); + StackTraceElement[] stackTraceElements = throwable.getStackTrace(); + if (stackTraceElements.length < 3 || !stackTraceElements[2].getClassName().equals("org.mini.vm.VmUtil")) { + throw new SecurityException("setThreadCreateHandler must be called by VmUtil, Please add handler from VmUtil"); + } + } + public static void setThreadCreateHandler(ThreadCreateHandler r) { + //if caller is not VmUtil.class, throw SecurityException + checkCaller(); createHandler = r; } + + public static ThreadCreateHandler getThreadCreateHandler() { + checkCaller(); + return createHandler; + } + + public enum State { + NEW, + RUNNABLE, + BLOCKED, + WAITING, + TIMED_WAITING, + TERMINATED; + } + + public State getState() { + // get current thread state + int state = RefNative.getStatus(this); + switch (state) { + case 0: + return State.NEW; + case 1: + return State.RUNNABLE; + case 2: + return State.BLOCKED; + case 3: + return State.WAITING; + case 4: + return State.WAITING; + default: + return State.TERMINATED; + } + } } diff --git a/minijvm/java/src/main/java/java/lang/ThreadGroup.java b/minijvm/java/src/main/java/java/lang/ThreadGroup.java index e9e66eef..763f9436 100644 --- a/minijvm/java/src/main/java/java/lang/ThreadGroup.java +++ b/minijvm/java/src/main/java/java/lang/ThreadGroup.java @@ -902,10 +902,6 @@ public void uncaughtException(Thread t, Throwable e) { */ @Deprecated public boolean allowThreadSuspension(boolean b) { - this.vmAllowSuspension = b; - if (!b) { - VM.unsuspendSomeThreads(); - } return true; } diff --git a/minijvm/java/src/main/java/org/mini/vm/VmUtil.java b/minijvm/java/src/main/java/org/mini/vm/VmUtil.java index 6d92c226..5a0a6645 100644 --- a/minijvm/java/src/main/java/org/mini/vm/VmUtil.java +++ b/minijvm/java/src/main/java/org/mini/vm/VmUtil.java @@ -85,7 +85,52 @@ static public URL getFileUrl(String sourceName, String[] paths) { return null; } - public static void setThreadCreateHandler(ThreadCreateHandler r) { - Thread.setThreadCreateHandler(r); + /** + * thread create handler + * 用于把线程创建事件通知给应用 + */ + static class ThreadHandler implements ThreadCreateHandler { + ThreadCreateHandler[] handlers; + + void addHandler(ThreadCreateHandler handler) { + if (handlers == null) { + handlers = new ThreadCreateHandler[]{handler}; + } else { + ThreadCreateHandler[] nhandlers = new ThreadCreateHandler[handlers.length + 1]; + System.arraycopy(handlers, 0, nhandlers, 0, handlers.length); + nhandlers[handlers.length] = handler; + handlers = nhandlers; + } + } + + void removeHandler(ThreadCreateHandler handler) { + for (int i = 0; i < handlers.length; i++) { + if (handlers[i] == handler) { + ThreadCreateHandler[] nhandlers = new ThreadCreateHandler[handlers.length - 1]; + System.arraycopy(handlers, 0, nhandlers, 0, i); + System.arraycopy(handlers, i + 1, nhandlers, i, handlers.length - i - 1); + handlers = nhandlers; + break; + } + } + } + + public void threadCreated(Thread t) { + //System.out.println("threadCreated:" + t.getName()); + for (ThreadCreateHandler handler : handlers) { + handler.threadCreated(t); + } + } + } + + static ThreadHandler threadHandler = new ThreadHandler(); + + public static void addThreadCreateHandler(ThreadCreateHandler r) { + threadHandler.addHandler(r); + Thread.setThreadCreateHandler(threadHandler); + } + + public static void removeThreadCreateHandler(ThreadCreateHandler r) { + threadHandler.removeHandler(r); } }