Include held locks in SIGQUIT thread dumps.
Handy if you have an ANR that's locking related. Quick tour:
at org.apache.harmony.dalvik.NativeTestTarget.emptyJniStaticSynchronizedMethod0(Native method)
- locked <0x60135aa8> (a java.lang.Class<org.apache.harmony.dalvik.NativeTestTarget>)
at java.lang.reflect.Method.invoke(Native method)
at C.whileTrue(Main.java:63)
at C.synchronizedOnClassString(Main.java:56)
- locked <0x60002a70> (a java.lang.Class<java.lang.String>)
at C.nestedSynchronizationWithTryCatch(Main.java:44)
- locked <0x61336b90> (a java.lang.String)
- locked <0x61336bd0> (a java.lang.String)
at C.nestedSynchronization(Main.java:35)
- locked <0x61336b18> (a java.lang.String)
- locked <0x61336b50> (a java.lang.String)
at C.synchronizedOnClassC(Main.java:30)
- locked <0x613366f8> (a java.lang.Class<C>)
at C.noLocks(Main.java:27)
at C.<clinit>(Main.java:24)
- locked <0x613366f8> (a java.lang.Class<C>)
at Main.main(Main.java:19)
A non-static synchronized native method works too:
at org.apache.harmony.dalvik.NativeTestTarget.emptyJniSynchronizedMethod0(Native method)
- locked <0x613371a8> (a org.apache.harmony.dalvik.NativeTestTarget)
...
Note that most stack traces don't look any different; the above is a
pathological example that exercises different kinds of locking. Testing
with system_server shows most threads don't hold any locks.
Future work (marked by TODO) is that explicit JNI MonitorEnter calls in
native code aren't shown.
Change-Id: I2747f5cddb4ef64b1935736f084a68fe8e4005e9
diff --git a/src/thread.cc b/src/thread.cc
index 9f88f5a..8fe0160 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -519,9 +519,10 @@
}
struct StackDumpVisitor : public StackVisitor {
- StackDumpVisitor(std::ostream& os, const Thread* thread)
- : StackVisitor(thread->GetManagedStack(), thread->GetTraceStack()), last_method(NULL),
- last_line_number(0), repetition_count(0), os(os), thread(thread), frame_count(0) {
+ StackDumpVisitor(std::ostream& os, const Thread* thread, Context* context, bool can_allocate)
+ : StackVisitor(thread->GetManagedStack(), thread->GetTraceStack(), context),
+ os(os), thread(thread), can_allocate(can_allocate),
+ last_method(NULL), last_line_number(0), repetition_count(0), frame_count(0) {
}
virtual ~StackDumpVisitor() {
@@ -565,19 +566,24 @@
<< ":" << line_number << ")";
}
os << "\n";
+ if (frame_count == 0) {
+ Monitor::DescribeWait(os, thread);
+ }
+ if (can_allocate) {
+ Monitor::DescribeLocks(os, this);
+ }
}
- if (frame_count++ == 0) {
- Monitor::DescribeWait(os, thread);
- }
+ ++frame_count;
return true;
}
+ std::ostream& os;
+ const Thread* thread;
+ bool can_allocate;
MethodHelper mh;
Method* last_method;
int last_line_number;
int repetition_count;
- std::ostream& os;
- const Thread* thread;
int frame_count;
};
@@ -587,7 +593,8 @@
DumpKernelStack(os, GetTid(), " kernel: ", false);
DumpNativeStack(os, GetTid(), " native: ", false);
}
- StackDumpVisitor dumper(os, this);
+ UniquePtr<Context> context(Context::Create());
+ StackDumpVisitor dumper(os, this, context.get(), !throwing_OutOfMemoryError_);
dumper.WalkStack();
}
@@ -999,7 +1006,8 @@
public:
CountStackDepthVisitor(const ManagedStack* stack,
const std::vector<TraceStackFrame>* trace_stack)
- : StackVisitor(stack, trace_stack), depth_(0), skip_depth_(0), skipping_(true) {}
+ : StackVisitor(stack, trace_stack, NULL),
+ depth_(0), skip_depth_(0), skipping_(true) {}
bool VisitFrame() {
// We want to skip frames up to and including the exception's constructor.
@@ -1039,8 +1047,8 @@
explicit BuildInternalStackTraceVisitor(const ManagedStack* stack,
const std::vector<TraceStackFrame>* trace_stack,
int skip_depth)
- : StackVisitor(stack, trace_stack), skip_depth_(skip_depth), count_(0), dex_pc_trace_(NULL),
- method_trace_(NULL) {}
+ : StackVisitor(stack, trace_stack, NULL),
+ skip_depth_(skip_depth), count_(0), dex_pc_trace_(NULL), method_trace_(NULL) {}
bool Init(int depth, const ScopedJniThreadState& ts) {
// Allocate method trace with an extra slot that will hold the PC trace
@@ -1551,7 +1559,7 @@
struct CurrentMethodVisitor : public StackVisitor {
CurrentMethodVisitor(const ManagedStack* stack,
const std::vector<TraceStackFrame>* trace_stack)
- : StackVisitor(stack, trace_stack), method_(NULL), dex_pc_(0), frame_id_(0) {}
+ : StackVisitor(stack, trace_stack, NULL), method_(NULL), dex_pc_(0), frame_id_(0) {}
virtual bool VisitFrame() {
Method* m = GetMethod();