Fix a VM abort caused by the HeapWorker thread.

After calling finalize method the HeapWorker needs to reacquire the
heapWorkerLock.  If the garbage collector is running, this resource
may not be released before the VM decides to suspend the HeapWorker
thread.  By transitioning the VMWAIT state in these situations, the
HeapWorker will not otherwise induce an abort.

Change-Id: I70ee47a9793d3d2f7fb24b1586aa43ce500a8767
diff --git a/vm/alloc/HeapWorker.c b/vm/alloc/HeapWorker.c
index 18c5aae..4521e34 100644
--- a/vm/alloc/HeapWorker.c
+++ b/vm/alloc/HeapWorker.c
@@ -191,6 +191,26 @@
     }
 }
 
+/*
+ * Acquires a mutex, transitioning to the VMWAIT state if the mutex is
+ * held.  This allows the thread to suspend while it waits for another
+ * thread to release the mutex.
+ */
+static void lockMutex(pthread_mutex_t *mu)
+{
+    Thread *self;
+    ThreadStatus oldStatus;
+
+    assert(mu != NULL);
+    if (dvmTryLockMutex(mu) != 0) {
+        self = dvmThreadSelf();
+        assert(self != NULL);
+        oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
+        dvmLockMutex(mu);
+        dvmChangeStatus(self, oldStatus);
+    }
+}
+
 static void callMethod(Thread *self, Object *obj, Method *method)
 {
     JValue unused;
@@ -223,7 +243,10 @@
     } else {
         dvmCallMethod(self, method, obj, &unused);
     }
-    dvmLockMutex(&gDvm.heapWorkerLock);
+    /*
+     * Reacquire the heap worker lock in a suspend-friendly way.
+     */
+    lockMutex(&gDvm.heapWorkerLock);
 
     gDvm.gcHeap->heapWorkerCurrentObject = NULL;
     gDvm.gcHeap->heapWorkerCurrentMethod = NULL;