diff --git a/src/share/vm/prims/unsafe.cpp b/src/share/vm/prims/unsafe.cpp index 915b732a9cc4cf0497568dcbe87abb3c819dd0e9..80c172290445792df0fdee81cdb5b5f709889c66 100644 --- a/src/share/vm/prims/unsafe.cpp +++ b/src/share/vm/prims/unsafe.cpp @@ -1503,17 +1503,6 @@ JVM_ENTRY(jboolean, CoroutineSupport_stealCoroutine(JNIEnv* env, jclass klass, j return true; JVM_END -JVM_ENTRY (jobjectArray, CoroutineSupport_getCoroutineStack(JNIEnv* env, jclass klass, jlong coroPtr)) - assert(EnableCoroutine, "pre-condition"); - - JvmtiVMObjectAllocEventCollector oam; - - Coroutine* coro = (Coroutine*)coroPtr; - - Handle stacktraces = ThreadService::dump_coroutine_stack_trace(coro, CHECK_NULL); - return (jobjectArray)JNIHandles::make_local(env, stacktraces()); -JVM_END - JVM_ENTRY (void, CoroutineSupport_checkAndThrowException0(JNIEnv* env, jclass klass, jlong coroPtr)) assert(EnableCoroutine, "pre-condition"); Coroutine* coro = (Coroutine*)coroPtr; @@ -1880,7 +1869,6 @@ JNINativeMethod coroutine_support_methods[] = { {CC"getNextCoroutine", CC"(J)"COR, FN_PTR(CoroutineSupport_getNextCoroutine)}, {CC"moveCoroutine", CC"(JJ)V", FN_PTR(CoroutineSupport_moveCoroutine)}, {CC"markThreadCoroutine", CC"(J"COBA")V", FN_PTR(CoroutineSupport_markThreadCoroutine)}, - {CC"getCoroutineStack", CC"(J)["STE, FN_PTR(CoroutineSupport_getCoroutineStack)}, {CC"checkAndThrowException0", CC"(J)V", FN_PTR(CoroutineSupport_checkAndThrowException0)}, }; diff --git a/src/share/vm/runtime/thread.cpp b/src/share/vm/runtime/thread.cpp index b2272c0f897d9f66411237482808d8d4fe5e89b1..c62e2492586982c6f3b5a1e85294313563875789 100644 --- a/src/share/vm/runtime/thread.cpp +++ b/src/share/vm/runtime/thread.cpp @@ -4299,6 +4299,20 @@ JavaThread* Threads::find_java_thread_from_java_tid(jlong java_tid) { java_thread = thread; break; } + + if (EnableCoroutine) { + for (Coroutine* co = thread->coroutine_list()->next(); + co != thread->coroutine_list(); co = co->next()) { + oop wtObj = com_alibaba_wisp_engine_WispTask::get_threadWrapper(co->wisp_task()); + // wtObj == 0 means coroutine is cached + if (!thread->is_exiting() && + wtObj != NULL && + java_tid == java_lang_Thread::thread_id(wtObj)) { + co->wisp_thread()->set_threadObj(wtObj); + return co->wisp_thread(); + } + } + } } return java_thread; } diff --git a/src/share/vm/runtime/vm_operations.cpp b/src/share/vm/runtime/vm_operations.cpp index 290c3357c0ceb2f19f55b0de901e9b31bc0a3f91..aa375940b7dc7431990454139b7667e17a94e033 100644 --- a/src/share/vm/runtime/vm_operations.cpp +++ b/src/share/vm/runtime/vm_operations.cpp @@ -323,6 +323,25 @@ void VM_ThreadDump::doit() { } ThreadSnapshot* ts = snapshot_thread(jt, tcl); _result->add_thread_snapshot(ts); + + if (EnableCoroutine) { + for (Coroutine* co = jt->coroutine_list()->next(); + co != jt->coroutine_list(); co = co->next()) { + oop tw = com_alibaba_wisp_engine_WispTask::get_threadWrapper(co->wisp_task()); + // skip exited wisp threads + if (tw == NULL) { + continue; + } + co->wisp_thread()->set_threadObj(tw); + + ThreadConcurrentLocks* wtcl = NULL; + if (_with_locked_synchronizers) { + wtcl = concurrent_locks.thread_concurrent_locks(co->wisp_thread()); + } + ThreadSnapshot* wts = snapshot_coroutine(co, wtcl); + _result->add_thread_snapshot(wts); + } + } } } else { // Snapshot threads in the given _threads array @@ -336,6 +355,29 @@ void VM_ThreadDump::doit() { continue; } + if (EnableCoroutine) { + jlong id = java_lang_Thread::thread_id(th()); + // this would traverse thread's coroutine list + JavaThread* jt = Threads::find_java_thread_from_java_tid(id); + if (jt->is_Wisp_thread()) { + Coroutine* co = ((WispThread*)jt)->coroutine(); + oop tw = com_alibaba_wisp_engine_WispTask::get_threadWrapper(co->wisp_task()); + // skip exited wisp threads + if (tw == NULL) { + continue; + } + co->wisp_thread()->set_threadObj(tw); + + ThreadConcurrentLocks* wtcl = NULL; + if (_with_locked_synchronizers) { + wtcl = concurrent_locks.thread_concurrent_locks(co->wisp_thread()); + } + ThreadSnapshot* wts = snapshot_coroutine(co, wtcl); + _result->add_thread_snapshot(wts); + return; + } + } + // Dump thread stack only if the thread is alive and not exiting // and not VM internal thread. JavaThread* jt = java_lang_Thread::thread(th()); @@ -363,33 +405,13 @@ ThreadSnapshot* VM_ThreadDump::snapshot_thread(JavaThread* java_thread, ThreadCo return snapshot; } -ThreadSnapshot* VM_CoroutineDump::snapshot_thread(JavaThread* java_thread, ThreadConcurrentLocks* tcl) { - ThreadSnapshot* snapshot = new ThreadSnapshot(java_thread); - snapshot->dump_stack_at_safepoint_for_coroutine(_target); +ThreadSnapshot* VM_ThreadDump::snapshot_coroutine(Coroutine* coro, ThreadConcurrentLocks* tcl) { + ThreadSnapshot* snapshot = new ThreadSnapshot(coro->wisp_thread()); + snapshot->dump_stack_at_safepoint_for_coroutine(coro, _max_depth, _with_locked_monitors); snapshot->set_concurrent_locks(tcl); return snapshot; } -VM_CoroutineDump::VM_CoroutineDump(ThreadDumpResult* result, Coroutine *target) { - assert(EnableCoroutine, "coroutine enabled"); - _result = result; - _target = target; -} - -bool VM_CoroutineDump::doit_prologue() { - assert(EnableCoroutine && Thread::current()->is_Java_thread(), "just checking"); - - return true; -} - -void VM_CoroutineDump::doit_epilogue() {} - -void VM_CoroutineDump::doit() { - ResourceMark rm; - - ThreadSnapshot* ts = snapshot_thread(_target->thread(), NULL); - _result->add_thread_snapshot(ts); -} volatile bool VM_Exit::_vm_exited = false; Thread * VM_Exit::_shutdown_thread = NULL; diff --git a/src/share/vm/runtime/vm_operations.hpp b/src/share/vm/runtime/vm_operations.hpp index 5886d2c6804005359e176d89180edea2dcb63804..33cbbd3b71cf44bd4b4185c641d58ada7d956fa2 100644 --- a/src/share/vm/runtime/vm_operations.hpp +++ b/src/share/vm/runtime/vm_operations.hpp @@ -42,7 +42,6 @@ template(Dummy) \ template(ThreadStop) \ template(ThreadDump) \ - template(CoroutineDump) \ template(PrintThreads) \ template(FindDeadlocks) \ template(ForceSafepoint) \ @@ -361,6 +360,7 @@ class VM_ThreadDump : public VM_Operation { bool _with_locked_synchronizers; ThreadSnapshot* snapshot_thread(JavaThread* java_thread, ThreadConcurrentLocks* tcl); + ThreadSnapshot* snapshot_coroutine(Coroutine* coro, ThreadConcurrentLocks* tcl); public: VM_ThreadDump(ThreadDumpResult* result, @@ -381,23 +381,6 @@ class VM_ThreadDump : public VM_Operation { void doit_epilogue(); }; -class VM_CoroutineDump : public VM_Operation { - private: - ThreadDumpResult* _result; - Coroutine * _target; - - ThreadSnapshot* snapshot_thread(JavaThread* java_thread, ThreadConcurrentLocks* tcl); - - public: - VM_CoroutineDump(ThreadDumpResult* result, Coroutine *target); - - VMOp_Type type() const { return VMOp_CoroutineDump; } - void doit(); - bool doit_prologue(); - void doit_epilogue(); -}; - - class VM_Exit: public VM_Operation { private: int _exit_code; diff --git a/src/share/vm/services/threadService.cpp b/src/share/vm/services/threadService.cpp index f861d926bdc1bf76ab32789fd37d02e0305a5220..288615998179bcd0b9f9c531935d6fe2aa71488d 100644 --- a/src/share/vm/services/threadService.cpp +++ b/src/share/vm/services/threadService.cpp @@ -37,6 +37,7 @@ #include "runtime/vmThread.hpp" #include "runtime/vm_operations.hpp" #include "services/threadService.hpp" +#include "runtime/coroutine.hpp" PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC @@ -281,31 +282,6 @@ Handle ThreadService::dump_stack_traces(GrowableArray* threads, return result_obj; } -// Dump stack trace of Coroutine and return StackTraceElement[]. -Handle ThreadService::dump_coroutine_stack_trace(Coroutine *coro, TRAPS) { - - assert(EnableCoroutine, "coroutine enabled"); - - ThreadDumpResult dump_result; - VM_CoroutineDump op(&dump_result, coro); - VMThread::execute(&op); - - // Allocate the resulting StackTraceElement[] object - - ResourceMark rm(THREAD); - - assert(dump_result.num_snapshots() == 1, "must only one stacktrace"); - ThreadStackTrace* stacktrace = dump_result.snapshots()->get_stack_trace(); - Handle stacktrace_h; - if (stacktrace == NULL) { - // No stack trace - stacktrace_h = Handle(); - } else { - // Construct an array of java/lang/StackTraceElement object - stacktrace_h = stacktrace->allocate_fill_stack_trace_element_array(CHECK_NH); - } - return stacktrace_h; -} void ThreadService::reset_contention_count_stat(JavaThread* thread) { ThreadStatistics* stat = thread->get_thread_stat(); @@ -655,7 +631,7 @@ void ThreadStackTrace::add_stack_frame(javaVFrame* jvf) { _depth++; } -void ThreadStackTrace::dump_stack_at_safepoint_for_coroutine(Coroutine *target) { +void ThreadStackTrace::dump_stack_at_safepoint_for_coroutine(Coroutine *target, int max_depth) { assert(SafepointSynchronize::is_at_safepoint(), "all threads are stopped"); Coroutine::CoroutineState state = target->state(); @@ -681,12 +657,18 @@ void ThreadStackTrace::dump_stack_at_safepoint_for_coroutine(Coroutine *target) } } + int count = 0; while (vf) { if (vf->is_java_frame()) { javaVFrame* jvf = javaVFrame::cast(vf); add_stack_frame(jvf); + count++; } vf = vf->sender(); + if (max_depth > 0 && count == max_depth) { + // Skip frames if more than maxDepth + break; + } } } @@ -900,9 +882,9 @@ void ThreadSnapshot::dump_stack_at_safepoint(int max_depth, bool with_locked_mon _stack_trace->dump_stack_at_safepoint(max_depth); } -void ThreadSnapshot::dump_stack_at_safepoint_for_coroutine(Coroutine *target) { - _stack_trace = new ThreadStackTrace(_thread, false); - _stack_trace->dump_stack_at_safepoint_for_coroutine(target); +void ThreadSnapshot::dump_stack_at_safepoint_for_coroutine(Coroutine *target, int max_depth, bool with_locked_monitors) { + _stack_trace = new ThreadStackTrace(_thread, with_locked_monitors); + _stack_trace->dump_stack_at_safepoint_for_coroutine(target, max_depth); } @@ -1016,6 +998,27 @@ ThreadsListEnumerator::ThreadsListEnumerator(Thread* cur_thread, MutexLockerEx ml(Threads_lock); for (JavaThread* jt = Threads::first(); jt != NULL; jt = jt->next()) { + if (!ThreadsListEnumerator::skipThread(jt, include_jvmti_agent_threads, include_jni_attaching_threads)) { + instanceHandle h(cur_thread, (instanceOop) jt->threadObj()); + _threads_array->append(h); + } + + if (EnableCoroutine) { + for (Coroutine* co = jt->coroutine_list()->next(); co != jt->coroutine_list(); co = co->next()) { + if (!ThreadsListEnumerator::skipThread(co->thread(), include_jvmti_agent_threads, include_jni_attaching_threads)) { + oop tw = com_alibaba_wisp_engine_WispTask::get_threadWrapper(co->wisp_task()); + // skip exited wisp threads + if (tw != NULL) { + instanceHandle hc(cur_thread, (instanceOop) tw); + _threads_array->append(hc); + } + } + } + } + } +} + +bool ThreadsListEnumerator::skipThread(JavaThread* jt, bool include_jvmti_agent_threads, bool include_jni_attaching_threads) { // skips JavaThreads in the process of exiting // and also skips VM internal JavaThreads // Threads in _thread_new or _thread_new_trans state are included. @@ -1024,20 +1027,18 @@ ThreadsListEnumerator::ThreadsListEnumerator(Thread* cur_thread, jt->is_exiting() || !java_lang_Thread::is_alive(jt->threadObj()) || jt->is_hidden_from_external_view()) { - continue; + return true; } // skip agent threads if (!include_jvmti_agent_threads && jt->is_jvmti_agent_thread()) { - continue; + return true; } // skip jni threads in the process of attaching if (!include_jni_attaching_threads && jt->is_attaching_via_jni()) { - continue; + return true; } - instanceHandle h(cur_thread, (instanceOop) jt->threadObj()); - _threads_array->append(h); - } + return false; } diff --git a/src/share/vm/services/threadService.hpp b/src/share/vm/services/threadService.hpp index 568585c2c8c0ed09844c791e9865dafb2509d69b..1a4d960e8bc0eccd95679053cb0954cda7cb62f3 100644 --- a/src/share/vm/services/threadService.hpp +++ b/src/share/vm/services/threadService.hpp @@ -105,8 +105,6 @@ public: static Handle dump_stack_traces(GrowableArray* threads, int num_threads, TRAPS); - static Handle dump_coroutine_stack_trace(Coroutine *coro, TRAPS); - static void reset_peak_thread_count(); static void reset_contention_count_stat(JavaThread* thread); static void reset_contention_time_stat(JavaThread* thread); @@ -243,7 +241,7 @@ public: ThreadConcurrentLocks* get_concurrent_locks() { return _concurrent_locks; } void dump_stack_at_safepoint(int max_depth, bool with_locked_monitors); - void dump_stack_at_safepoint_for_coroutine(Coroutine *target); + void dump_stack_at_safepoint_for_coroutine(Coroutine *target, int max_depth, bool with_locked_monitors); void set_concurrent_locks(ThreadConcurrentLocks* l) { _concurrent_locks = l; } void oops_do(OopClosure* f); void metadata_do(void f(Metadata*)); @@ -268,7 +266,7 @@ class ThreadStackTrace : public CHeapObj { void add_stack_frame(javaVFrame* jvf); void dump_stack_at_safepoint(int max_depth); - void dump_stack_at_safepoint_for_coroutine(Coroutine *target); + void dump_stack_at_safepoint_for_coroutine(Coroutine *target, int max_depth); Handle allocate_fill_stack_trace_element_array(TRAPS); void oops_do(OopClosure* f); void metadata_do(void f(Metadata*)); @@ -392,6 +390,7 @@ class DeadlockCycle : public CHeapObj { class ThreadsListEnumerator : public StackObj { private: GrowableArray* _threads_array; + static bool skipThread(JavaThread* jt, bool include_jvmti_agent_threads, bool include_jni_attaching_threads); public: ThreadsListEnumerator(Thread* cur_thread, bool include_jvmti_agent_threads = false,