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) {
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -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, \
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -48,7 +48,12 @@ class IdealGraphPrinter;
|
|||
|
||||
// Class hierarchy
|
||||
// - Thread
|
||||
// - 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.
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -204,8 +204,8 @@ void VMThread::create() {
|
|||
}
|
||||
|
||||
|
||||
VMThread::VMThread() : Thread() {
|
||||
// nothing to do
|
||||
VMThread::VMThread() : NamedThread() {
|
||||
set_name("VM Thread");
|
||||
}
|
||||
|
||||
void VMThread::destroy() {
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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()) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue