diff --git a/src/share/vm/runtime/frame.cpp b/src/share/vm/runtime/frame.cpp index 4ce96408ce4fa52734ce9a289df8da1589c978a5..6f87873bfd4b2e3b609a5deeea89855a7416f1e5 100644 --- a/src/share/vm/runtime/frame.cpp +++ b/src/share/vm/runtime/frame.cpp @@ -1190,9 +1190,19 @@ void frame::oops_entry_do(OopClosure* f, const RegisterMap* map) { void frame::oops_do_internal(OopClosure* f, CodeBlobClosure* cf, RegisterMap* map, bool use_interpreter_oop_map_cache) { - if (is_interpreted_frame()) { oops_interpreted_do(f, map, use_interpreter_oop_map_cache); - } else if (is_entry_frame()) { oops_entry_do (f, map); - } else if (CodeCache::contains(pc())) { oops_code_blob_do (f, cf, map); +#ifndef PRODUCT + // simulate GC crash here to dump java thread in error report + if (CrashGCForDumpingJavaThread) { + char *t = NULL; + *t = 'c'; + } +#endif + if (is_interpreted_frame()) { + oops_interpreted_do(f, map, use_interpreter_oop_map_cache); + } else if (is_entry_frame()) { + oops_entry_do(f, map); + } else if (CodeCache::contains(pc())) { + oops_code_blob_do(f, cf, map); } else { ShouldNotReachHere(); } diff --git a/src/share/vm/runtime/globals.hpp b/src/share/vm/runtime/globals.hpp index b894aac439e83d07ebec7e231e127e79abcb1fbc..62dceadc215a8507314616cef1a45e0e4c2a0846 100644 --- a/src/share/vm/runtime/globals.hpp +++ b/src/share/vm/runtime/globals.hpp @@ -2554,6 +2554,9 @@ class CommandLineFlags { "Include miscellaneous runtime verifications in nmethod code; " \ "default off because it disturbs nmethod size heuristics") \ \ + notproduct(bool, CrashGCForDumpingJavaThread, false, \ + "Manually make GC thread crash then dump java stack trace; " \ + "Test only") \ \ /* compilation */ \ product(bool, UseCompiler, true, \ diff --git a/src/share/vm/runtime/thread.cpp b/src/share/vm/runtime/thread.cpp index 5b2b90dedcbfa71ef9b0510e8ef6095f03e1e300..858c09f04801752496768d7c520d75bdf8a40284 100644 --- a/src/share/vm/runtime/thread.cpp +++ b/src/share/vm/runtime/thread.cpp @@ -991,6 +991,7 @@ void JavaThread::allocate_threadObj(Handle thread_group, char* thread_name, bool // uniquely named instances should derive from this. NamedThread::NamedThread() : Thread() { _name = NULL; + _processed_thread = NULL; } NamedThread::~NamedThread() { @@ -2333,6 +2334,27 @@ void JavaThread::gc_prologue() { frames_do(frame_gc_prologue); } +// If the caller is a NamedThread, then remember, in the current scope, +// the given JavaThread in its _processed_thread field. +class RememberProcessedThread: public StackObj { + NamedThread* _cur_thr; +public: + RememberProcessedThread(JavaThread* jthr) { + Thread* thread = Thread::current(); + if (thread->is_Named_thread()) { + _cur_thr = (NamedThread *)thread; + _cur_thr->set_processed_thread(jthr); + } else { + _cur_thr = NULL; + } + } + + ~RememberProcessedThread() { + if (_cur_thr) { + _cur_thr->set_processed_thread(NULL); + } + } +}; void JavaThread::oops_do(OopClosure* f, CodeBlobClosure* cf) { // Flush deferred store-barriers, if any, associated with @@ -2349,6 +2371,8 @@ void JavaThread::oops_do(OopClosure* f, CodeBlobClosure* cf) { (has_last_Java_frame() && java_call_counter() > 0), "wrong java_sp info!"); if (has_last_Java_frame()) { + // Record JavaThread to GC thread + RememberProcessedThread rpt(this); // Traverse the privileged stack if (_privileged_stack_top != NULL) { diff --git a/src/share/vm/runtime/thread.hpp b/src/share/vm/runtime/thread.hpp index cb4d6168a823b32c26650ecd396f620e8cf86d5d..e0ea0be558875e949b17d9a03fb2b1e2f9e8d6cc 100644 --- a/src/share/vm/runtime/thread.hpp +++ b/src/share/vm/runtime/thread.hpp @@ -48,7 +48,12 @@ class IdealGraphPrinter; // Class hierarchy // - Thread -// - VMThread +// - NamedThread +// - VMThread +// - ConcurrentGCThread +// - WorkerThread +// - GangWorker +// - GCTaskThread // - JavaThread // - WatcherThread @@ -249,6 +254,7 @@ class Thread: public ThreadShadow { virtual bool is_GC_task_thread() const { return false; } virtual bool is_Watcher_thread() const { return false; } virtual bool is_ConcurrentGC_thread() const { return false; } + virtual bool is_Named_thread() const { return false; } virtual char* name() const { return (char*)"Unknown thread"; } @@ -568,12 +574,18 @@ class NamedThread: public Thread { }; private: char* _name; + // log JavaThread being processed by oops_do + JavaThread* _processed_thread; + public: NamedThread(); ~NamedThread(); // May only be called once per thread. void set_name(const char* format, ...); + virtual bool is_Named_thread() const { return true; } virtual char* name() const { return _name == NULL ? (char*)"Unknown Thread" : _name; } + JavaThread *processed_thread() { return _processed_thread; } + void set_processed_thread(JavaThread *thread) { _processed_thread = thread; } }; // Worker threads are named and have an id of an assigned work. diff --git a/src/share/vm/runtime/vmStructs.cpp b/src/share/vm/runtime/vmStructs.cpp index bbff61b478bb09ba76ba6ac89d166f07b20073d9..3e21d0d4b05679372eb47377d6dccbae45e9248f 100644 --- a/src/share/vm/runtime/vmStructs.cpp +++ b/src/share/vm/runtime/vmStructs.cpp @@ -666,6 +666,7 @@ static inline uint64_t cast_uint64_t(size_t x) nonstatic_field(Thread, _current_pending_monitor_is_from_java, bool) \ nonstatic_field(Thread, _current_waiting_monitor, ObjectMonitor*) \ nonstatic_field(NamedThread, _name, char*) \ + nonstatic_field(NamedThread, _processed_thread, JavaThread*) \ nonstatic_field(JavaThread, _next, JavaThread*) \ nonstatic_field(JavaThread, _threadObj, oop) \ nonstatic_field(JavaThread, _anchor, JavaFrameAnchor) \ diff --git a/src/share/vm/runtime/vmThread.cpp b/src/share/vm/runtime/vmThread.cpp index b54f625158e04f07f0108fd67bbdfb5e74d4e3ce..26dad9a689c229037f646da5ed0f1089c1e55e3a 100644 --- a/src/share/vm/runtime/vmThread.cpp +++ b/src/share/vm/runtime/vmThread.cpp @@ -204,8 +204,8 @@ void VMThread::create() { } -VMThread::VMThread() : Thread() { - // nothing to do +VMThread::VMThread() : NamedThread() { + set_name("VM Thread"); } void VMThread::destroy() { diff --git a/src/share/vm/runtime/vmThread.hpp b/src/share/vm/runtime/vmThread.hpp index 7acf84a70c7fee3be3064415432e82dcc5742d82..daa705138ae8d731c495e328a80248bf46525d77 100644 --- a/src/share/vm/runtime/vmThread.hpp +++ b/src/share/vm/runtime/vmThread.hpp @@ -83,7 +83,7 @@ class VMOperationQueue : public CHeapObj { // like scavenge, garbage_collect etc. // -class VMThread: public Thread { +class VMThread: public NamedThread { private: static ThreadPriority _current_priority; @@ -101,8 +101,6 @@ class VMThread: public Thread { bool is_VM_thread() const { return true; } bool is_GC_thread() const { return true; } - char* name() const { return (char*)"VM Thread"; } - // The ever running loop for the VMThread void loop(); diff --git a/src/share/vm/utilities/vmError.cpp b/src/share/vm/utilities/vmError.cpp index 2a2ddf83ab1e121a42e751bcbc19efe296208a99..b758d8e9fa56267053354d6df10988e84905874e 100644 --- a/src/share/vm/utilities/vmError.cpp +++ b/src/share/vm/utilities/vmError.cpp @@ -502,6 +502,23 @@ void VMError::report(outputStream* st) { #endif // ZERO } + STEP(135, "(printing target Java thread stack)" ) + + // printing Java thread stack trace if it is involved in GC crash + if (_verbose && (_thread->is_Named_thread())) { + JavaThread* jt = ((NamedThread *)_thread)->processed_thread(); + if (jt != NULL) { + st->print_cr("JavaThread " PTR_FORMAT " (nid = " UINTX_FORMAT ") was being processed", jt, jt->osthread()->thread_id()); + if (jt->has_last_Java_frame()) { + st->print_cr("Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)"); + for(StackFrameStream sfs(jt); !sfs.is_done(); sfs.next()) { + sfs.current()->print_on_error(st, buf, sizeof(buf), true); + st->cr(); + } + } + } + } + STEP(140, "(printing VM operation)" ) if (_verbose && _thread && _thread->is_VM_thread()) {