OSDN Git Service

am 813a3a2d: Merge "If dalvik wants ASCII casing, it needs to ask for it."
[android-x86/dalvik.git] / vm / Thread.cpp
index 2676ca4..205167e 100644 (file)
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define ATRACE_TAG ATRACE_TAG_DALVIK
+
 /*
  * Thread support.
  */
 #include <sys/resource.h>
 #include <sys/mman.h>
 #include <signal.h>
+#include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
 
-#ifdef HAVE_ANDROID_OS
-#include <dirent.h>
-#endif
-
 #if defined(HAVE_PRCTL)
 #include <sys/prctl.h>
 #endif
@@ -42,6 +41,7 @@
 #include "interp/Jit.h"         // need for self verification
 #endif
 
+ #include <cutils/trace.h>
 
 /* desktop Linux needs a little help with gettid() */
 #if defined(HAVE_GETTID) && !defined(HAVE_ANDROID_OS)
@@ -1281,6 +1281,7 @@ bool dvmCreateInterpThread(Object* threadObj, int reqStackSize)
             "thread has already been started");
         freeThread(newThread);
         dvmReleaseTrackedAlloc(vmThreadObj, NULL);
+        return false;
     }
 
     /*
@@ -1301,8 +1302,8 @@ bool dvmCreateInterpThread(Object* threadObj, int reqStackSize)
 
     ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
     pthread_t threadHandle;
-    int cc = pthread_create(&threadHandle, &threadAttr, interpThreadStart,
-                            newThread);
+    int cc = pthread_create(&threadHandle, &threadAttr, interpThreadStart, newThread);
+    pthread_attr_destroy(&threadAttr);
     dvmChangeStatus(self, oldStatus);
 
     if (cc != 0) {
@@ -1311,11 +1312,13 @@ bool dvmCreateInterpThread(Object* threadObj, int reqStackSize)
          * resource limits.  VirtualMachineError is probably too severe,
          * so use OutOfMemoryError.
          */
-        ALOGE("Thread creation failed (err=%s)", strerror(errno));
 
         dvmSetFieldObject(threadObj, gDvm.offJavaLangThread_vmThread, NULL);
 
-        dvmThrowOutOfMemoryError("thread creation failed");
+        ALOGE("pthread_create (stack size %d bytes) failed: %s", stackSize, strerror(cc));
+        dvmThrowExceptionFmt(gDvm.exOutOfMemoryError,
+                             "pthread_create (stack size %d bytes) failed: %s",
+                             stackSize, strerror(cc));
         goto fail;
     }
 
@@ -1636,7 +1639,6 @@ bool dvmCreateInternalThread(pthread_t* pHandle, const char* name,
 {
     InternalStartArgs* pArgs;
     Object* systemGroup;
-    pthread_attr_t threadAttr;
     volatile Thread* newThread = NULL;
     volatile int createStatus = 0;
 
@@ -1653,13 +1655,13 @@ bool dvmCreateInternalThread(pthread_t* pHandle, const char* name,
     pArgs->pThread = &newThread;
     pArgs->pCreateStatus = &createStatus;
 
+    pthread_attr_t threadAttr;
     pthread_attr_init(&threadAttr);
-    //pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED);
 
-    if (pthread_create(pHandle, &threadAttr, internalThreadStart,
-            pArgs) != 0)
-    {
-        ALOGE("internal thread creation failed");
+    int cc = pthread_create(pHandle, &threadAttr, internalThreadStart, pArgs);
+    pthread_attr_destroy(&threadAttr);
+    if (cc != 0) {
+        ALOGE("internal thread creation failed: %s", strerror(cc));
         free(pArgs->name);
         free(pArgs);
         return false;
@@ -2146,13 +2148,14 @@ void dvmDetachCurrentThread()
         gDvm.nonDaemonThreadCount--;        // guarded by thread list lock
 
         if (gDvm.nonDaemonThreadCount == 0) {
-            int cc;
-
             ALOGV("threadid=%d: last non-daemon thread", self->threadId);
             //dvmDumpAllThreads(false);
             // cond var guarded by threadListLock, which we already hold
-            cc = pthread_cond_signal(&gDvm.vmExitCond);
-            assert(cc == 0);
+            int cc = pthread_cond_signal(&gDvm.vmExitCond);
+            if (cc != 0) {
+                ALOGE("pthread_cond_signal(&gDvm.vmExitCond) failed: %s", strerror(cc));
+                dvmAbort();
+            }
         }
     }
 
@@ -2630,7 +2633,6 @@ void dvmResumeAllThreads(SuspendCause why)
 {
     Thread* self = dvmThreadSelf();
     Thread* thread;
-    int cc;
 
     lockThreadSuspend("res-all", why);  /* one suspend/resume at a time */
     LOG_THREAD("threadid=%d: ResumeAll starting", self->threadId);
@@ -2708,8 +2710,11 @@ void dvmResumeAllThreads(SuspendCause why)
      * which may choose to wake up.  No need to wait for them.
      */
     lockThreadSuspendCount();
-    cc = pthread_cond_broadcast(&gDvm.threadSuspendCountCond);
-    assert(cc == 0);
+    int cc = pthread_cond_broadcast(&gDvm.threadSuspendCountCond);
+    if (cc != 0) {
+        ALOGE("pthread_cond_broadcast(&gDvm.threadSuspendCountCond) failed: %s", strerror(cc));
+        dvmAbort();
+    }
     unlockThreadSuspendCount();
 
     LOG_THREAD("threadid=%d: ResumeAll complete", self->threadId);
@@ -2723,7 +2728,6 @@ void dvmUndoDebuggerSuspensions()
 {
     Thread* self = dvmThreadSelf();
     Thread* thread;
-    int cc;
 
     lockThreadSuspend("undo", SUSPEND_FOR_DEBUG);
     LOG_THREAD("threadid=%d: UndoDebuggerSusp starting", self->threadId);
@@ -2757,8 +2761,11 @@ void dvmUndoDebuggerSuspensions()
      * which may choose to wake up.  No need to wait for them.
      */
     lockThreadSuspendCount();
-    cc = pthread_cond_broadcast(&gDvm.threadSuspendCountCond);
-    assert(cc == 0);
+    int cc = pthread_cond_broadcast(&gDvm.threadSuspendCountCond);
+    if (cc != 0) {
+        ALOGE("pthread_cond_broadcast(&gDvm.threadSuspendCountCond) failed: %s", strerror(cc));
+        dvmAbort();
+    }
     unlockThreadSuspendCount();
 
     unlockThreadSuspend();
@@ -2851,6 +2858,7 @@ static bool fullSuspendCheck(Thread* self)
         ThreadStatus oldStatus = self->status;      /* should be RUNNING */
         self->status = THREAD_SUSPENDED;
 
+        ATRACE_BEGIN("DVM Suspend");
         while (self->suspendCount != 0) {
             /*
              * Wait for wakeup signal, releasing lock.  The act of releasing
@@ -2860,6 +2868,7 @@ static bool fullSuspendCheck(Thread* self)
             dvmWaitCond(&gDvm.threadSuspendCountCond,
                     &gDvm.threadSuspendCountLock);
         }
+        ATRACE_END();
         assert(self->suspendCount == 0 && self->dbgSuspendCount == 0);
         self->status = oldStatus;
         LOG_THREAD("threadid=%d: self-reviving, status=%d",
@@ -3266,6 +3275,36 @@ static void getSchedulerStats(SchedulerStats* stats, pid_t tid) {
     }
 }
 
+static bool shouldShowNativeStack(Thread* thread) {
+    // In native code somewhere in the VM? That's interesting.
+    if (thread->status == THREAD_VMWAIT) {
+        return true;
+    }
+
+    // In an Object.wait variant? That's not interesting.
+    if (thread->status == THREAD_TIMED_WAIT || thread->status == THREAD_WAIT) {
+        return false;
+    }
+
+    // The Signal Catcher thread? That's not interesting.
+    if (thread->status == THREAD_RUNNING) {
+        return false;
+    }
+
+    // In some other native method? That's interesting.
+    // We don't just check THREAD_NATIVE because native methods will be in
+    // state THREAD_SUSPENDED if they're calling back into the VM, or THREAD_MONITOR
+    // if they're blocked on a monitor, or one of the thread-startup states if
+    // it's early enough in their life cycle (http://b/7432159).
+    u4* fp = thread->interpSave.curFrame;
+    if (fp == NULL) {
+        // The thread has no managed frames, so native frames are all there is.
+        return true;
+    }
+    const Method* currentMethod = SAVEAREA_FROM_FP(fp)->method;
+    return currentMethod != NULL && dvmIsNativeMethod(currentMethod);
+}
+
 /*
  * Print information about the specified thread.
  *
@@ -3344,16 +3383,7 @@ void dvmDumpThreadEx(const DebugOutputTarget* target, Thread* thread,
 
     dumpSchedStat(target, thread->systemTid);
 
-    /*
-     * Grab the native stack, if possible.
-     *
-     * The native thread is still running, even if the Dalvik side is
-     * suspended.  This means the thread can move itself out of NATIVE state
-     * while we're in here, shifting to SUSPENDED after a brief moment at
-     * RUNNING.  At that point the native stack isn't all that interesting,
-     * though, so if we fail to dump it there's little lost.
-     */
-    if (thread->status == THREAD_NATIVE || thread->status == THREAD_VMWAIT) {
+    if (shouldShowNativeStack(thread)) {
         dvmDumpNativeStack(target, thread->systemTid);
     }
 
@@ -3484,10 +3514,7 @@ void dvmDumpAllThreadsEx(const DebugOutputTarget* target, bool grabLock)
     }
 
 #ifdef HAVE_ANDROID_OS
-    char path[64];
-    snprintf(path, sizeof(path), "/proc/%d/task", getpid());
-
-    DIR* d = opendir(path);
+    DIR* d = opendir("/proc/self/task");
     if (d != NULL) {
         dirent* entry = NULL;
         bool first = true;
@@ -3572,7 +3599,7 @@ void dvmNukeThread(Thread* thread)
     ALOGD("Sent, pausing to let debuggerd run");
     usleep(8 * 1000 * 1000);    // TODO: timed-wait until debuggerd finishes
 
-    /* ignore SIGSEGV so the eventual dmvAbort() doesn't notify debuggerd */
+    /* ignore SIGSEGV so the eventual dvmAbort() doesn't notify debuggerd */
     signal(SIGSEGV, SIG_IGN);
     ALOGD("Continuing");
 }