From 9d885a3d822a5ec5a4fa103b1754efa710bd2652 Mon Sep 17 00:00:00 2001 From: minqi Date: Fri, 11 Dec 2009 11:09:49 -0800 Subject: [PATCH] 6361589: Print out stack trace for target thread of GC crash Summary: If GC crashed with java thread involved, print out the java stack trace in error report Reviewed-by: never, ysr, coleenp, dholmes --- src/share/vm/runtime/frame.cpp | 16 +++++++++++++--- src/share/vm/runtime/globals.hpp | 3 +++ src/share/vm/runtime/thread.cpp | 24 ++++++++++++++++++++++++ src/share/vm/runtime/thread.hpp | 14 +++++++++++++- src/share/vm/runtime/vmStructs.cpp | 1 + src/share/vm/runtime/vmThread.cpp | 4 ++-- src/share/vm/runtime/vmThread.hpp | 4 +--- src/share/vm/utilities/vmError.cpp | 17 +++++++++++++++++ 8 files changed, 74 insertions(+), 9 deletions(-) diff --git a/src/share/vm/runtime/frame.cpp b/src/share/vm/runtime/frame.cpp index 4ce96408c..6f87873bf 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 b894aac43..62dceadc2 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 5b2b90ded..858c09f04 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 cb4d6168a..e0ea0be55 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 bbff61b47..3e21d0d4b 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 b54f62515..26dad9a68 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 7acf84a70..daa705138 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 2a2ddf83a..b758d8e9f 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()) { -- GitLab