Fix a heap lock/thread list lock deadlock.
We had an uncaught OOME whose uncaught exception handler -- running
with the thread lock held -- was trying to cause a GC while some
other thread had the heap lock and was waiting for the thread list
lock.
Change-Id: I22177129562268837127d9edcc63ef5e93054bdf
diff --git a/src/thread.cc b/src/thread.cc
index d68d1db..af6c29d 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -751,34 +751,9 @@
}
if (peer_ != NULL) {
- Object* group = gThread_group->GetObject(peer_);
-
- // Handle any pending exception.
- if (IsExceptionPending()) {
- // Get and clear the exception.
- Object* exception = GetException();
- ClearException();
-
- // If the thread has its own handler, use that.
- Object* handler = gThread_uncaughtHandler->GetObject(peer_);
- if (handler == NULL) {
- // Otherwise use the thread group's default handler.
- handler = group;
- }
-
- // Call the handler.
- Method* m = handler->GetClass()->FindVirtualMethodForVirtualOrInterface(gUncaughtExceptionHandler_uncaughtException);
- Object* args[2];
- args[0] = peer_;
- args[1] = exception;
- m->Invoke(this, handler, reinterpret_cast<byte*>(&args), NULL);
-
- // If the handler threw, clear that exception too.
- ClearException();
- }
-
// this.group.removeThread(this);
// group can be null if we're in the compiler or a test.
+ Object* group = gThread_group->GetObject(peer_);
if (group != NULL) {
Method* m = group->GetClass()->FindVirtualMethodForVirtualOrInterface(gThreadGroup_removeThread);
Object* args = peer_;
@@ -816,6 +791,35 @@
delete long_jump_context_;
}
+void Thread::HandleUncaughtExceptions() {
+ if (!IsExceptionPending()) {
+ return;
+ }
+
+ ScopedThreadStateChange tsc(this, Thread::kRunnable);
+
+ // Get and clear the exception.
+ Object* exception = GetException();
+ ClearException();
+
+ // If the thread has its own handler, use that.
+ Object* handler = gThread_uncaughtHandler->GetObject(peer_);
+ if (handler == NULL) {
+ // Otherwise use the thread group's default handler.
+ handler = gThread_group->GetObject(peer_);
+ }
+
+ // Call the handler.
+ Method* m = handler->GetClass()->FindVirtualMethodForVirtualOrInterface(gUncaughtExceptionHandler_uncaughtException);
+ Object* args[2];
+ args[0] = peer_;
+ args[1] = exception;
+ m->Invoke(this, handler, reinterpret_cast<byte*>(&args), NULL);
+
+ // If the handler threw, clear that exception too.
+ ClearException();
+}
+
size_t Thread::NumSirtReferences() {
size_t count = 0;
for (StackIndirectReferenceTable* cur = top_sirt_; cur; cur = cur->Link()) {
@@ -1186,13 +1190,22 @@
msg, (throwing_OutOfMemoryError_ ? " (recursive case)" : ""));
if (!throwing_OutOfMemoryError_) {
throwing_OutOfMemoryError_ = true;
- ThrowNewException("Ljava/lang/OutOfMemoryError;", msg);
+ ThrowNewException("Ljava/lang/OutOfMemoryError;", NULL);
} else {
SetException(pre_allocated_OutOfMemoryError_);
}
throwing_OutOfMemoryError_ = false;
}
+
+Thread* Thread::CurrentFromGdb() const {
+ return Thread::Current();
+}
+
+void Thread::DumpFromGdb() const {
+ Dump(std::cerr);
+}
+
class CatchBlockStackVisitor : public Thread::StackVisitor {
public:
CatchBlockStackVisitor(Class* to_find, Context* ljc)