Fix "holding ThreadListLock while doing condition variable wait on HeapLock"

Now we release the ThreadListLock if we are going to wait on the heap condition variable in WaitForConcurrentGC.

Change-Id: I506c8ff93f4b79ee74c98b7936a7d155be833b90
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 72ab76e..6640430 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -211,6 +211,7 @@
 	src/runtime.cc \
 	src/runtime_support.cc \
 	src/scoped_thread_list_lock.cc \
+	src/scoped_thread_list_lock_releaser.cc \
 	src/signal_catcher.cc \
 	src/space.cc \
 	src/stack.cc \
diff --git a/src/heap.cc b/src/heap.cc
index 0c4c6ff..55a8afe 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -30,6 +30,7 @@
 #include "object_utils.h"
 #include "os.h"
 #include "scoped_heap_lock.h"
+#include "scoped_thread_list_lock_releaser.h"
 #include "ScopedLocalRef.h"
 #include "space.h"
 #include "stl_util.h"
@@ -737,8 +738,10 @@
   // Busy wait for GC to finish
   if (is_gc_running_) {
     uint64_t wait_start = NanoTime();
+
     do {
       ScopedThreadStateChange tsc(Thread::Current(), kVmWait);
+      ScopedThreadListLockReleaser list_lock_releaser;
       condition_->Wait(*lock_);
     } while (is_gc_running_);
     uint64_t wait_time = NanoTime() - wait_start;
diff --git a/src/scoped_thread_list_lock_releaser.cc b/src/scoped_thread_list_lock_releaser.cc
new file mode 100644
index 0000000..3ac22a5
--- /dev/null
+++ b/src/scoped_thread_list_lock_releaser.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "scoped_thread_list_lock_releaser.h"
+
+#include "runtime.h"
+#include "thread_list.h"
+
+namespace art {
+
+ScopedThreadListLockReleaser::ScopedThreadListLockReleaser() {
+  if (Thread::Current()->held_mutexes_[kThreadListLock] > 0) {
+    Runtime::Current()->GetThreadList()->thread_list_lock_.Unlock();
+    unlocked_ = true;
+  } else {
+    unlocked_ = false;
+  }
+}
+
+ScopedThreadListLockReleaser::~ScopedThreadListLockReleaser() {
+  if (unlocked_) {
+    Runtime::Current()->GetThreadList()->thread_list_lock_.Lock();
+  }
+}
+
+}  // namespace art
diff --git a/src/scoped_thread_list_lock_releaser.h b/src/scoped_thread_list_lock_releaser.h
new file mode 100644
index 0000000..af656d5
--- /dev/null
+++ b/src/scoped_thread_list_lock_releaser.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_SCOPED_THREAD_LIST_LOCK_RELEASER_H_
+#define ART_SRC_SCOPED_THREAD_LIST_LOCK_RELEASER_H_
+
+#include "macros.h"
+
+namespace art {
+
+class ScopedThreadListLockReleaser {
+ public:
+  ScopedThreadListLockReleaser();
+  ~ScopedThreadListLockReleaser();
+
+ private:
+  // Whether or not we unlocked the thread list lock.
+  bool unlocked_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedThreadListLockReleaser);
+};
+
+}  // namespace art
+
+#endif  // ART_SRC_SCOPED_THREAD_LIST_LOCK_RELEASER_H_
diff --git a/src/thread.h b/src/thread.h
index c674ded..ad07498 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -651,6 +651,7 @@
   EntryPoints entrypoints_;
 
  private:
+  friend class ScopedThreadListLockReleaser;
   DISALLOW_COPY_AND_ASSIGN(Thread);
 };
 
diff --git a/src/thread_list.h b/src/thread_list.h
index 36cd094..ef475fe 100644
--- a/src/thread_list.h
+++ b/src/thread_list.h
@@ -92,6 +92,7 @@
 
   friend class Thread;
   friend class ScopedThreadListLock;
+  friend class ScopedThreadListLockReleaser;
 
   DISALLOW_COPY_AND_ASSIGN(ThreadList);
 };