mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 14:24:46 +02:00
6361589: Print out stack trace for target thread of GC crash
If GC crashed with java thread involved, print out the java stack trace in error report Reviewed-by: never, ysr, coleenp, dholmes
This commit is contained in:
parent
baf249687c
commit
4f656a451e
8 changed files with 74 additions and 9 deletions
|
@ -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) {
|
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);
|
#ifndef PRODUCT
|
||||||
} else if (is_entry_frame()) { oops_entry_do (f, map);
|
// simulate GC crash here to dump java thread in error report
|
||||||
} else if (CodeCache::contains(pc())) { oops_code_blob_do (f, cf, map);
|
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 {
|
} else {
|
||||||
ShouldNotReachHere();
|
ShouldNotReachHere();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2554,6 +2554,9 @@ class CommandLineFlags {
|
||||||
"Include miscellaneous runtime verifications in nmethod code; " \
|
"Include miscellaneous runtime verifications in nmethod code; " \
|
||||||
"default off because it disturbs nmethod size heuristics") \
|
"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 */ \
|
/* compilation */ \
|
||||||
product(bool, UseCompiler, true, \
|
product(bool, UseCompiler, true, \
|
||||||
|
|
|
@ -991,6 +991,7 @@ void JavaThread::allocate_threadObj(Handle thread_group, char* thread_name, bool
|
||||||
// uniquely named instances should derive from this.
|
// uniquely named instances should derive from this.
|
||||||
NamedThread::NamedThread() : Thread() {
|
NamedThread::NamedThread() : Thread() {
|
||||||
_name = NULL;
|
_name = NULL;
|
||||||
|
_processed_thread = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
NamedThread::~NamedThread() {
|
NamedThread::~NamedThread() {
|
||||||
|
@ -2333,6 +2334,27 @@ void JavaThread::gc_prologue() {
|
||||||
frames_do(frame_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) {
|
void JavaThread::oops_do(OopClosure* f, CodeBlobClosure* cf) {
|
||||||
// Flush deferred store-barriers, if any, associated with
|
// 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!");
|
(has_last_Java_frame() && java_call_counter() > 0), "wrong java_sp info!");
|
||||||
|
|
||||||
if (has_last_Java_frame()) {
|
if (has_last_Java_frame()) {
|
||||||
|
// Record JavaThread to GC thread
|
||||||
|
RememberProcessedThread rpt(this);
|
||||||
|
|
||||||
// Traverse the privileged stack
|
// Traverse the privileged stack
|
||||||
if (_privileged_stack_top != NULL) {
|
if (_privileged_stack_top != NULL) {
|
||||||
|
|
|
@ -48,7 +48,12 @@ class IdealGraphPrinter;
|
||||||
|
|
||||||
// Class hierarchy
|
// Class hierarchy
|
||||||
// - Thread
|
// - Thread
|
||||||
|
// - NamedThread
|
||||||
// - VMThread
|
// - VMThread
|
||||||
|
// - ConcurrentGCThread
|
||||||
|
// - WorkerThread
|
||||||
|
// - GangWorker
|
||||||
|
// - GCTaskThread
|
||||||
// - JavaThread
|
// - JavaThread
|
||||||
// - WatcherThread
|
// - WatcherThread
|
||||||
|
|
||||||
|
@ -249,6 +254,7 @@ class Thread: public ThreadShadow {
|
||||||
virtual bool is_GC_task_thread() const { return false; }
|
virtual bool is_GC_task_thread() const { return false; }
|
||||||
virtual bool is_Watcher_thread() const { return false; }
|
virtual bool is_Watcher_thread() const { return false; }
|
||||||
virtual bool is_ConcurrentGC_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"; }
|
virtual char* name() const { return (char*)"Unknown thread"; }
|
||||||
|
|
||||||
|
@ -568,12 +574,18 @@ class NamedThread: public Thread {
|
||||||
};
|
};
|
||||||
private:
|
private:
|
||||||
char* _name;
|
char* _name;
|
||||||
|
// log JavaThread being processed by oops_do
|
||||||
|
JavaThread* _processed_thread;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NamedThread();
|
NamedThread();
|
||||||
~NamedThread();
|
~NamedThread();
|
||||||
// May only be called once per thread.
|
// May only be called once per thread.
|
||||||
void set_name(const char* format, ...);
|
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; }
|
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.
|
// Worker threads are named and have an id of an assigned work.
|
||||||
|
|
|
@ -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_pending_monitor_is_from_java, bool) \
|
||||||
nonstatic_field(Thread, _current_waiting_monitor, ObjectMonitor*) \
|
nonstatic_field(Thread, _current_waiting_monitor, ObjectMonitor*) \
|
||||||
nonstatic_field(NamedThread, _name, char*) \
|
nonstatic_field(NamedThread, _name, char*) \
|
||||||
|
nonstatic_field(NamedThread, _processed_thread, JavaThread*) \
|
||||||
nonstatic_field(JavaThread, _next, JavaThread*) \
|
nonstatic_field(JavaThread, _next, JavaThread*) \
|
||||||
nonstatic_field(JavaThread, _threadObj, oop) \
|
nonstatic_field(JavaThread, _threadObj, oop) \
|
||||||
nonstatic_field(JavaThread, _anchor, JavaFrameAnchor) \
|
nonstatic_field(JavaThread, _anchor, JavaFrameAnchor) \
|
||||||
|
|
|
@ -204,8 +204,8 @@ void VMThread::create() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VMThread::VMThread() : Thread() {
|
VMThread::VMThread() : NamedThread() {
|
||||||
// nothing to do
|
set_name("VM Thread");
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMThread::destroy() {
|
void VMThread::destroy() {
|
||||||
|
|
|
@ -83,7 +83,7 @@ class VMOperationQueue : public CHeapObj {
|
||||||
// like scavenge, garbage_collect etc.
|
// like scavenge, garbage_collect etc.
|
||||||
//
|
//
|
||||||
|
|
||||||
class VMThread: public Thread {
|
class VMThread: public NamedThread {
|
||||||
private:
|
private:
|
||||||
static ThreadPriority _current_priority;
|
static ThreadPriority _current_priority;
|
||||||
|
|
||||||
|
@ -101,8 +101,6 @@ class VMThread: public Thread {
|
||||||
bool is_VM_thread() const { return true; }
|
bool is_VM_thread() const { return true; }
|
||||||
bool is_GC_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
|
// The ever running loop for the VMThread
|
||||||
void loop();
|
void loop();
|
||||||
|
|
||||||
|
|
|
@ -502,6 +502,23 @@ void VMError::report(outputStream* st) {
|
||||||
#endif // ZERO
|
#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)" )
|
STEP(140, "(printing VM operation)" )
|
||||||
|
|
||||||
if (_verbose && _thread && _thread->is_VM_thread()) {
|
if (_verbose && _thread && _thread->is_VM_thread()) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue