libcorkscrew native stacks, mutex ranking, and better ScopedThreadListLock.
This change uses libcorkscrew to show native stacks for threads in kNative or,
unlike dalvikvm, kVmWait --- working on the runtime directly I've found it
somewhat useful to be able to see _which_ internal resource we're waiting on.
We can always take that back out (or make it oatexecd-only) if it turns out to
be too noisy/confusing for app developers.
This change also lets us rank mutexes and enforce -- in oatexecd -- that you
take locks in a specific order.
Both of these helped me test the third novelty: removing the heap locking from
ScopedThreadListLock. I've manually inspected all the callers and added a
ScopedHeapLock where I think one is necessary. In manual testing, this makes
jdb a lot less prone to locking us up. There still seems to be a problem with
the JDWP VirtualMachine.Resume command, but I'll look at that separately. This
is a big enough and potentially disruptive enough change already.
Change-Id: Iad974358919d0e00674662dc8a69cc65878cfb5c
diff --git a/src/thread.cc b/src/thread.cc
index 74107d5..1c521c1 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -404,6 +404,7 @@
}
os << GetState()
<< ",Thread*=" << this
+ << ",peer=" << peer_
<< ",\"" << *name_ << "\""
<< "]";
}
@@ -438,6 +439,10 @@
return (peer_ != NULL) ? reinterpret_cast<String*>(gThread_name->GetObject(peer_)) : NULL;
}
+void Thread::GetThreadName(std::string& name) const {
+ name.assign(*name_);
+}
+
void Thread::DumpState(std::ostream& os) const {
std::string group_name;
int priority;
@@ -586,6 +591,10 @@
};
void Thread::DumpStack(std::ostream& os) const {
+ // If we're currently in native code, dump that stack before dumping the managed stack.
+ if (GetState() == Thread::kNative || GetState() == Thread::kVmWait) {
+ DumpNativeStack(os);
+ }
StackDumpVisitor dumper(os, this);
WalkStack(&dumper);
}
@@ -681,7 +690,7 @@
static void ReportThreadSuspendTimeout(Thread* waiting_thread) {
Runtime* runtime = Runtime::Current();
std::ostringstream ss;
- ss << "Thread suspend timeout; waiting thread=" << *waiting_thread << "\n";
+ ss << "Thread suspend timeout waiting for thread " << *waiting_thread << "\n";
runtime->DumpLockHolders(ss);
ss << "\n";
runtime->GetThreadList()->DumpLocked(ss);
@@ -841,6 +850,7 @@
trace_stack_(new std::vector<TraceStackFrame>),
name_(new std::string("<native thread without managed peer>")) {
CHECK_EQ((sizeof(Thread) % 4), 0U) << sizeof(Thread);
+ memset(&held_mutexes_[0], 0, sizeof(held_mutexes_));
}
void MonitorExitVisitor(const Object* object, void*) {
@@ -1664,4 +1674,23 @@
return os;
}
+void Thread::CheckRank(MutexRank rank, bool is_locking) {
+ if (is_locking) {
+ if (held_mutexes_[rank] == 0) {
+ bool bad_mutexes_held = false;
+ for (int i = kMaxMutexRank; i > rank; --i) {
+ if (held_mutexes_[i] != 0) {
+ LOG(ERROR) << "holding " << static_cast<MutexRank>(i) << " while " << (is_locking ? "locking" : "unlocking") << " " << rank;
+ bad_mutexes_held = true;
+ }
+ }
+ CHECK(!bad_mutexes_held);
+ }
+ ++held_mutexes_[rank];
+ } else {
+ CHECK_GT(held_mutexes_[rank], 0U);
+ --held_mutexes_[rank];
+ }
+}
+
} // namespace art