* 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
#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)
"thread has already been started");
freeThread(newThread);
dvmReleaseTrackedAlloc(vmThreadObj, NULL);
+ return false;
}
/*
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) {
* 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;
}
{
InternalStartArgs* pArgs;
Object* systemGroup;
- pthread_attr_t threadAttr;
volatile Thread* newThread = NULL;
volatile int createStatus = 0;
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;
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();
+ }
}
}
{
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);
* 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);
{
Thread* self = dvmThreadSelf();
Thread* thread;
- int cc;
lockThreadSuspend("undo", SUSPEND_FOR_DEBUG);
LOG_THREAD("threadid=%d: UndoDebuggerSusp starting", self->threadId);
* 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();
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
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",
}
}
+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.
*
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);
}
}
#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;
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");
}