summaryrefslogtreecommitdiffstats
path: root/vm/Thread.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'vm/Thread.cpp')
-rw-r--r--vm/Thread.cpp339
1 files changed, 222 insertions, 117 deletions
diff --git a/vm/Thread.cpp b/vm/Thread.cpp
index 28182d6f2..aa2352af2 100644
--- a/vm/Thread.cpp
+++ b/vm/Thread.cpp
@@ -30,6 +30,10 @@
#include <errno.h>
#include <fcntl.h>
+#ifdef HAVE_ANDROID_OS
+#include <dirent.h>
+#endif
+
#if defined(HAVE_PRCTL)
#include <sys/prctl.h>
#endif
@@ -54,7 +58,7 @@ pid_t gettid() { return syscall(__NR_gettid);}
// Change this to enable logging on cgroup errors
#define ENABLE_CGROUP_ERR_LOGGING 0
-// change this to LOGV/LOGD to debug thread activity
+// change this to ALOGV/ALOGD to debug thread activity
#define LOG_THREAD LOGVV
/*
@@ -251,13 +255,13 @@ bool dvmThreadStartup()
/* allocate a TLS slot */
if (pthread_key_create(&gDvm.pthreadKeySelf, threadExitCheck) != 0) {
- LOGE("ERROR: pthread_key_create failed");
+ ALOGE("ERROR: pthread_key_create failed");
return false;
}
/* test our pthread lib */
if (pthread_getspecific(gDvm.pthreadKeySelf) != NULL)
- LOGW("WARNING: newly-created pthread TLS slot is not NULL");
+ ALOGW("WARNING: newly-created pthread TLS slot is not NULL");
/* prep thread-related locks and conditions */
dvmInitMutex(&gDvm.threadListLock);
@@ -278,7 +282,7 @@ bool dvmThreadStartup()
gDvm.threadIdMap = dvmAllocBitVector(kMaxThreadId, false);
- thread = allocThread(gDvm.stackSize);
+ thread = allocThread(gDvm.mainThreadStackSize);
if (thread == NULL)
return false;
@@ -472,7 +476,7 @@ static void lockThreadSuspend(const char* who, SuspendCause why)
* Could be two app threads both want to patch predicted
* chaining cells around the same time.
*/
- LOGI("threadid=%d ODD: want thread-suspend lock (%s:%s),"
+ ALOGI("threadid=%d ODD: want thread-suspend lock (%s:%s),"
" it's held, no suspend pending",
self->threadId, who, getSuspendCauseStr(why));
} else {
@@ -484,7 +488,7 @@ static void lockThreadSuspend(const char* who, SuspendCause why)
if (sleepIter == 0)
startWhen = dvmGetRelativeTimeUsec();
if (!dvmIterativeSleep(sleepIter++, kSpinSleepTime, startWhen)) {
- LOGE("threadid=%d: couldn't get thread-suspend lock (%s:%s),"
+ ALOGE("threadid=%d: couldn't get thread-suspend lock (%s:%s),"
" bailing",
self->threadId, who, getSuspendCauseStr(why));
/* threads are not suspended, thread dump could crash */
@@ -548,12 +552,12 @@ void dvmSlayDaemons()
gDvm.offJavaLangThread_daemon))
{
/* should never happen; suspend it with the rest */
- LOGW("threadid=%d: non-daemon id=%d still running at shutdown?!",
+ ALOGW("threadid=%d: non-daemon id=%d still running at shutdown?!",
threadId, target->threadId);
}
std::string threadName(dvmGetThreadName(target));
- LOGV("threadid=%d: suspending daemon id=%d name='%s'",
+ ALOGV("threadid=%d: suspending daemon id=%d name='%s'",
threadId, target->threadId, threadName.c_str());
/* mark as suspended */
@@ -604,7 +608,7 @@ void dvmSlayDaemons()
if (target->status == THREAD_RUNNING) {
if (!complained)
- LOGD("threadid=%d not ready yet", target->threadId);
+ ALOGD("threadid=%d not ready yet", target->threadId);
allSuspended = false;
/* keep going so we log each running daemon once */
}
@@ -613,12 +617,12 @@ void dvmSlayDaemons()
}
if (allSuspended) {
- LOGV("threadid=%d: all daemons have suspended", threadId);
+ ALOGV("threadid=%d: all daemons have suspended", threadId);
break;
} else {
if (!complained) {
complained = true;
- LOGD("threadid=%d: waiting briefly for daemon suspension",
+ ALOGD("threadid=%d: waiting briefly for daemon suspension",
threadId);
}
}
@@ -684,7 +688,7 @@ bool dvmPrepMainThread()
Method* init;
JValue unused;
- LOGV("+++ finishing prep on main VM thread");
+ ALOGV("+++ finishing prep on main VM thread");
/* main thread is always first in list at this point */
thread = gDvm.threadList;
@@ -695,14 +699,14 @@ bool dvmPrepMainThread()
* we create an instance of them.
*/
if (!dvmInitClass(gDvm.classJavaLangClass)) {
- LOGE("'Class' class failed to initialize");
+ ALOGE("'Class' class failed to initialize");
return false;
}
if (!dvmInitClass(gDvm.classJavaLangThreadGroup) ||
!dvmInitClass(gDvm.classJavaLangThread) ||
!dvmInitClass(gDvm.classJavaLangVMThread))
{
- LOGE("thread classes failed to initialize");
+ ALOGE("thread classes failed to initialize");
return false;
}
@@ -716,7 +720,7 @@ bool dvmPrepMainThread()
*/
threadObj = dvmAllocObject(gDvm.classJavaLangThread, ALLOC_DEFAULT);
if (threadObj == NULL) {
- LOGE("unable to allocate main thread object");
+ ALOGE("unable to allocate main thread object");
return false;
}
dvmReleaseTrackedAlloc(threadObj, NULL);
@@ -732,7 +736,7 @@ bool dvmPrepMainThread()
dvmCallMethod(thread, init, threadObj, &unused, groupObj, threadNameStr,
THREAD_NORM_PRIORITY, false);
if (dvmCheckException(thread)) {
- LOGE("exception thrown while constructing main thread object");
+ ALOGE("exception thrown while constructing main thread object");
return false;
}
@@ -741,7 +745,7 @@ bool dvmPrepMainThread()
*/
vmThreadObj = dvmAllocObject(gDvm.classJavaLangVMThread, ALLOC_DEFAULT);
if (vmThreadObj == NULL) {
- LOGE("unable to allocate main vmthread object");
+ ALOGE("unable to allocate main vmthread object");
return false;
}
dvmReleaseTrackedAlloc(vmThreadObj, NULL);
@@ -750,7 +754,7 @@ bool dvmPrepMainThread()
"(Ljava/lang/Thread;)V");
dvmCallMethod(thread, init, vmThreadObj, &unused, threadObj);
if (dvmCheckException(thread)) {
- LOGE("exception thrown while constructing main vmthread object");
+ ALOGE("exception thrown while constructing main vmthread object");
return false;
}
@@ -778,7 +782,7 @@ bool dvmPrepMainThread()
*/
Object* systemLoader = dvmGetSystemClassLoader();
if (systemLoader == NULL) {
- LOGW("WARNING: system class loader is NULL (setting main ctxt)");
+ ALOGW("WARNING: system class loader is NULL (setting main ctxt)");
/* keep going? */
} else {
dvmSetFieldObject(threadObj, gDvm.offJavaLangThread_contextClassLoader,
@@ -899,7 +903,7 @@ static bool prepareThread(Thread* thread)
thread->handle = pthread_self();
thread->systemTid = dvmGetSysThreadId();
- //LOGI("SYSTEM TID IS %d (pid is %d)", (int) thread->systemTid,
+ //ALOGI("SYSTEM TID IS %d (pid is %d)", (int) thread->systemTid,
// (int) getpid());
/*
* If we were called by dvmAttachCurrentThread, the self value is
@@ -907,7 +911,7 @@ static bool prepareThread(Thread* thread)
*/
setThreadSelf(thread);
- LOGV("threadid=%d: interp stack at %p",
+ ALOGV("threadid=%d: interp stack at %p",
thread->threadId, thread->interpStackStart - thread->interpStackSize);
/*
@@ -981,7 +985,7 @@ static void freeThread(Thread* thread)
free(interpStackBottom);
#else
if (munmap(interpStackBottom, thread->interpStackSize) != 0)
- LOGW("munmap(thread stack) failed");
+ ALOGW("munmap(thread stack) failed");
#endif
}
@@ -1020,7 +1024,7 @@ static void setThreadSelf(Thread* thread)
* here to ensure we clean up after ourselves.
*/
if (thread != NULL) {
- LOGE("pthread_setspecific(%p) failed, err=%d", thread, cc);
+ ALOGE("pthread_setspecific(%p) failed, err=%d", thread, cc);
dvmAbort(); /* the world is fundamentally hosed */
}
}
@@ -1053,11 +1057,11 @@ static void threadExitCheck(void* arg)
Thread* self = (Thread*) arg;
assert(self != NULL);
- LOGV("threadid=%d: threadExitCheck(%p) count=%d",
+ ALOGV("threadid=%d: threadExitCheck(%p) count=%d",
self->threadId, arg, self->threadExitCheckCount);
if (self->status == THREAD_ZOMBIE) {
- LOGW("threadid=%d: Weird -- shouldn't be in threadExitCheck",
+ ALOGW("threadid=%d: Weird -- shouldn't be in threadExitCheck",
self->threadId);
return;
}
@@ -1066,17 +1070,17 @@ static void threadExitCheck(void* arg)
/*
* Spin a couple of times to let other destructors fire.
*/
- LOGD("threadid=%d: thread exiting, not yet detached (count=%d)",
+ ALOGD("threadid=%d: thread exiting, not yet detached (count=%d)",
self->threadId, self->threadExitCheckCount);
self->threadExitCheckCount++;
int cc = pthread_setspecific(gDvm.pthreadKeySelf, self);
if (cc != 0) {
- LOGE("threadid=%d: unable to re-add thread to TLS",
+ ALOGE("threadid=%d: unable to re-add thread to TLS",
self->threadId);
dvmAbort();
}
} else {
- LOGE("threadid=%d: native thread exited without detaching",
+ ALOGE("threadid=%d: native thread exited without detaching",
self->threadId);
dvmAbort();
}
@@ -1100,7 +1104,7 @@ static void assignThreadId(Thread* thread)
*/
int num = dvmAllocBit(gDvm.threadIdMap);
if (num < 0) {
- LOGE("Ran out of thread IDs");
+ ALOGE("Ran out of thread IDs");
dvmAbort(); // TODO: make this a non-fatal error result
}
@@ -1197,13 +1201,13 @@ static void setThreadName(const char *threadName)
buf[sizeof(buf)-1] = '\0';
int err = pthread_setname_np(pthread_self(), buf);
if (err != 0) {
- LOGW("Unable to set the name of current thread to '%s': %s",
+ ALOGW("Unable to set the name of current thread to '%s': %s",
buf, strerror(err));
}
#elif defined(HAVE_PRCTL)
prctl(PR_SET_NAME, (unsigned long) s, 0, 0, 0);
#else
- LOGD("No way to set current thread's name (%s)", s);
+ ALOGD("No way to set current thread's name (%s)", s);
#endif
}
@@ -1307,7 +1311,7 @@ bool dvmCreateInterpThread(Object* threadObj, int reqStackSize)
* resource limits. VirtualMachineError is probably too severe,
* so use OutOfMemoryError.
*/
- LOGE("Thread creation failed (err=%s)", strerror(errno));
+ ALOGE("Thread creation failed (err=%s)", strerror(errno));
dvmSetFieldObject(threadObj, gDvm.offJavaLangThread_vmThread, NULL);
@@ -1529,10 +1533,10 @@ static void* interpThreadStart(void* arg)
Method* run = self->threadObj->clazz->vtable[gDvm.voffJavaLangThread_run];
JValue unused;
- LOGV("threadid=%d: calling run()", self->threadId);
+ ALOGV("threadid=%d: calling run()", self->threadId);
assert(strcmp(run->name, "run") == 0);
dvmCallMethod(self, run, self->threadObj, &unused);
- LOGV("threadid=%d: exiting", self->threadId);
+ ALOGV("threadid=%d: exiting", self->threadId);
/*
* Remove the thread from various lists, report its death, and free
@@ -1562,7 +1566,7 @@ static void threadExitUncaughtException(Thread* self, Object* group)
Object* handlerObj;
Method* uncaughtHandler;
- LOGW("threadid=%d: thread exiting with uncaught exception (group=%p)",
+ ALOGW("threadid=%d: thread exiting with uncaught exception (group=%p)",
self->threadId, group);
assert(group != NULL);
@@ -1594,14 +1598,14 @@ static void threadExitUncaughtException(Thread* self, Object* group)
"uncaughtException", "(Ljava/lang/Thread;Ljava/lang/Throwable;)V");
if (uncaughtHandler != NULL) {
- //LOGI("+++ calling %s.uncaughtException",
+ //ALOGI("+++ calling %s.uncaughtException",
// handlerObj->clazz->descriptor);
JValue unused;
dvmCallMethod(self, uncaughtHandler, handlerObj, &unused,
self->threadObj, exception);
} else {
/* should be impossible, but handle it anyway */
- LOGW("WARNING: no 'uncaughtException' method in class %s",
+ ALOGW("WARNING: no 'uncaughtException' method in class %s",
handlerObj->clazz->descriptor);
dvmSetException(self, exception);
dvmLogExceptionStackTrace();
@@ -1655,7 +1659,7 @@ bool dvmCreateInternalThread(pthread_t* pHandle, const char* name,
if (pthread_create(pHandle, &threadAttr, internalThreadStart,
pArgs) != 0)
{
- LOGE("internal thread creation failed");
+ ALOGE("internal thread creation failed");
free(pArgs->name);
free(pArgs);
return false;
@@ -1683,7 +1687,7 @@ bool dvmCreateInternalThread(pthread_t* pHandle, const char* name,
pthread_cond_wait(&gDvm.threadStartCond, &gDvm.threadListLock);
if (newThread == NULL) {
- LOGW("internal thread create failed (createStatus=%d)", createStatus);
+ ALOGW("internal thread create failed (createStatus=%d)", createStatus);
assert(createStatus < 0);
/* don't free pArgs -- if pthread_create succeeded, child owns it */
dvmUnlockThreadList();
@@ -1890,7 +1894,7 @@ bool dvmAttachCurrentThread(const JavaVMAttachArgs* pArgs, bool isDaemon)
dvmCallMethod(self, init, threadObj, &unused, (Object*)pArgs->group,
threadNameStr, os_getThreadPriorityFromSystem(), isDaemon);
if (dvmCheckException(self)) {
- LOGE("exception thrown while constructing attached thread object");
+ ALOGE("exception thrown while constructing attached thread object");
goto fail_unlink;
}
@@ -1909,7 +1913,7 @@ bool dvmAttachCurrentThread(const JavaVMAttachArgs* pArgs, bool isDaemon)
* way that ensures another thread can't call start() on it.
*/
if (dvmGetFieldObject(threadObj, gDvm.offJavaLangThread_vmThread) != NULL) {
- LOGW("WOW: thread start hijack");
+ ALOGW("WOW: thread start hijack");
dvmThrowIllegalThreadStateException(
"thread has already been started");
/* We don't want to free anything associated with the thread
@@ -2016,7 +2020,7 @@ void dvmDetachCurrentThread()
}
if (!topIsNative) {
- LOGE("ERROR: detaching thread with interp frames (count=%d)",
+ ALOGE("ERROR: detaching thread with interp frames (count=%d)",
curDepth);
dvmDumpThread(self, false);
dvmAbort();
@@ -2110,7 +2114,7 @@ void dvmDetachCurrentThread()
dvmLockMutex(&traceState->startStopLock);
if (traceState->traceEnabled) {
- LOGI("threadid=%d: waiting for method trace to finish",
+ ALOGI("threadid=%d: waiting for method trace to finish",
self->threadId);
while (traceState->traceEnabled) {
dvmWaitCond(&traceState->threadExitCond,
@@ -2144,7 +2148,7 @@ void dvmDetachCurrentThread()
if (gDvm.nonDaemonThreadCount == 0) {
int cc;
- LOGV("threadid=%d: last non-daemon thread", self->threadId);
+ 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);
@@ -2152,7 +2156,7 @@ void dvmDetachCurrentThread()
}
}
- LOGV("threadid=%d: bye!", self->threadId);
+ ALOGV("threadid=%d: bye!", self->threadId);
releaseThreadId(self);
dvmUnlockThreadList();
@@ -2261,7 +2265,7 @@ void dvmSuspendSelf(bool jdwpActivity)
* If we got here via waitForDebugger(), don't do this part.
*/
if (jdwpActivity) {
- //LOGI("threadid=%d: clearing wait-for-event (my handle=%08x)",
+ //ALOGI("threadid=%d: clearing wait-for-event (my handle=%08x)",
// self->threadId, (int) self->handle);
dvmJdwpClearWaitForEventThread(gDvm.jdwpState);
}
@@ -2276,7 +2280,7 @@ void dvmSuspendSelf(bool jdwpActivity)
* dump event is pending (assuming SignalCatcher was resumed for
* just long enough to try to grab the thread-suspend lock).
*/
- LOGD("threadid=%d: still suspended after undo (sc=%d dc=%d)",
+ ALOGD("threadid=%d: still suspended after undo (sc=%d dc=%d)",
self->threadId, self->suspendCount, self->dbgSuspendCount);
}
}
@@ -2318,12 +2322,12 @@ int dvmRaiseThreadPriorityIfNeeded(Thread* thread, int* pSavedThreadPrio,
errno = 0;
*pSavedThreadPrio = getpriority(PRIO_PROCESS, thread->systemTid);
if (errno != 0) {
- LOGW("Unable to get priority for threadid=%d sysTid=%d",
+ ALOGW("Unable to get priority for threadid=%d sysTid=%d",
thread->threadId, thread->systemTid);
return 0;
}
if (get_sched_policy(thread->systemTid, pSavedThreadPolicy) != 0) {
- LOGW("Unable to get policy for threadid=%d sysTid=%d",
+ ALOGW("Unable to get policy for threadid=%d sysTid=%d",
thread->threadId, thread->systemTid);
return 0;
}
@@ -2335,10 +2339,10 @@ int dvmRaiseThreadPriorityIfNeeded(Thread* thread, int* pSavedThreadPrio,
*/
if (*pSavedThreadPolicy == SP_BACKGROUND) {
if (set_sched_policy(thread->systemTid, SP_FOREGROUND) != 0) {
- LOGW("Couldn't set fg policy on tid %d", thread->systemTid);
+ ALOGW("Couldn't set fg policy on tid %d", thread->systemTid);
} else {
changeFlags |= kChangedPolicy;
- LOGD("Temporarily moving tid %d to fg (was %d)",
+ ALOGD("Temporarily moving tid %d to fg (was %d)",
thread->systemTid, *pSavedThreadPolicy);
}
}
@@ -2350,11 +2354,11 @@ int dvmRaiseThreadPriorityIfNeeded(Thread* thread, int* pSavedThreadPrio,
if (*pSavedThreadPrio > 0) {
const int kHigher = 0;
if (setpriority(PRIO_PROCESS, thread->systemTid, kHigher) != 0) {
- LOGW("Couldn't raise priority on tid %d to %d",
+ ALOGW("Couldn't raise priority on tid %d to %d",
thread->systemTid, kHigher);
} else {
changeFlags |= kChangedPriority;
- LOGD("Temporarily raised priority on tid %d (%d -> %d)",
+ ALOGD("Temporarily raised priority on tid %d (%d -> %d)",
thread->systemTid, *pSavedThreadPrio, kHigher);
}
}
@@ -2370,10 +2374,10 @@ void dvmResetThreadPriority(Thread* thread, int changeFlags,
{
if ((changeFlags & kChangedPolicy) != 0) {
if (set_sched_policy(thread->systemTid, savedThreadPolicy) != 0) {
- LOGW("NOTE: couldn't reset tid %d to (%d)",
+ ALOGW("NOTE: couldn't reset tid %d to (%d)",
thread->systemTid, savedThreadPolicy);
} else {
- LOGD("Restored policy of %d to %d",
+ ALOGD("Restored policy of %d to %d",
thread->systemTid, savedThreadPolicy);
}
}
@@ -2381,10 +2385,10 @@ void dvmResetThreadPriority(Thread* thread, int changeFlags,
if ((changeFlags & kChangedPriority) != 0) {
if (setpriority(PRIO_PROCESS, thread->systemTid, savedThreadPrio) != 0)
{
- LOGW("NOTE: couldn't reset priority on thread %d to %d",
+ ALOGW("NOTE: couldn't reset priority on thread %d to %d",
thread->systemTid, savedThreadPrio);
} else {
- LOGD("Restored priority on %d to %d",
+ ALOGD("Restored priority on %d to %d",
thread->systemTid, savedThreadPrio);
}
}
@@ -2457,7 +2461,7 @@ static void waitForThreadSuspend(Thread* self, Thread* thread)
*/
if (gDvmJit.pJitEntryTable && retryCount > 0 &&
gDvmJit.hasNewChain && thread->inJitCodeCache) {
- LOGD("JIT unchain all for threadid=%d", thread->threadId);
+ ALOGD("JIT unchain all for threadid=%d", thread->threadId);
dvmJitUnchainAll();
}
#endif
@@ -2468,7 +2472,7 @@ static void waitForThreadSuspend(Thread* self, Thread* thread)
*/
if (!dvmIterativeSleep(sleepIter++, spinSleepTime, startWhen)) {
if (spinSleepTime != FIRST_SLEEP) {
- LOGW("threadid=%d: spin on suspend #%d threadid=%d (pcf=%d)",
+ ALOGW("threadid=%d: spin on suspend #%d threadid=%d (pcf=%d)",
self->threadId, retryCount,
thread->threadId, priChangeFlags);
if (retryCount > 1) {
@@ -2483,11 +2487,11 @@ static void waitForThreadSuspend(Thread* self, Thread* thread)
spinSleepTime = MORE_SLEEP;
if (retryCount++ == kMaxRetries) {
- LOGE("Fatal spin-on-suspend, dumping threads");
+ ALOGE("Fatal spin-on-suspend, dumping threads");
dvmDumpAllThreads(false);
/* log this after -- long traces will scroll off log */
- LOGE("threadid=%d: stuck on threadid=%d, giving up",
+ ALOGE("threadid=%d: stuck on threadid=%d, giving up",
self->threadId, thread->threadId);
/* try to get a debuggerd dump from the spinning thread */
@@ -2499,7 +2503,7 @@ static void waitForThreadSuspend(Thread* self, Thread* thread)
}
if (complained) {
- LOGW("threadid=%d: spin on suspend resolved in %lld msec",
+ ALOGW("threadid=%d: spin on suspend resolved in %lld msec",
self->threadId,
(dvmGetRelativeTimeUsec() - firstStartWhen) / 1000);
//dvmDumpThread(thread, false); /* suspended, so dump is safe */
@@ -2988,13 +2992,13 @@ static Object* getStaticThreadGroup(const char* fieldName)
groupField = dvmFindStaticField(gDvm.classJavaLangThreadGroup,
fieldName, "Ljava/lang/ThreadGroup;");
if (groupField == NULL) {
- LOGE("java.lang.ThreadGroup does not have an '%s' field", fieldName);
+ ALOGE("java.lang.ThreadGroup does not have an '%s' field", fieldName);
dvmThrowInternalError("bad definition for ThreadGroup");
return NULL;
}
groupObj = dvmGetStaticFieldObject(groupField);
if (groupObj == NULL) {
- LOGE("java.lang.ThreadGroup.%s not initialized", fieldName);
+ ALOGE("java.lang.ThreadGroup.%s not initialized", fieldName);
dvmThrowInternalError(NULL);
return NULL;
}
@@ -3033,7 +3037,7 @@ Thread* dvmGetThreadFromThreadObject(Object* vmThreadObj)
}
if (thread == NULL) {
- LOGW("WARNING: vmThreadObj=%p has thread=%p, not in thread list",
+ ALOGW("WARNING: vmThreadObj=%p has thread=%p, not in thread list",
vmThreadObj, (Thread*)vmData);
vmData = 0;
}
@@ -3176,7 +3180,7 @@ static int getSchedulerGroup(int tid, char* buf, size_t bufLen)
return -1;
out_bad_data:
- LOGE("Bad cgroup data {%s}", lineBuf);
+ ALOGE("Bad cgroup data {%s}", lineBuf);
snprintf(buf, bufLen, "[data-parse-failed]");
fclose(fp);
return -1;
@@ -3207,6 +3211,61 @@ const char* dvmGetThreadStatusStr(ThreadStatus status)
}
}
+static void dumpSchedStat(const DebugOutputTarget* target, pid_t tid) {
+#ifdef HAVE_ANDROID_OS
+ /* get some bits from /proc/self/stat */
+ ProcStatData procStatData;
+ if (!dvmGetThreadStats(&procStatData, tid)) {
+ /* failed, use zeroed values */
+ memset(&procStatData, 0, sizeof(procStatData));
+ }
+
+ /* grab the scheduler stats for this thread */
+ char schedstatBuf[64];
+ snprintf(schedstatBuf, sizeof(schedstatBuf), "/proc/self/task/%d/schedstat", tid);
+ int schedstatFd = open(schedstatBuf, O_RDONLY);
+ strcpy(schedstatBuf, "0 0 0"); /* show this if open/read fails */
+ if (schedstatFd >= 0) {
+ ssize_t bytes;
+ bytes = read(schedstatFd, schedstatBuf, sizeof(schedstatBuf) - 1);
+ close(schedstatFd);
+ if (bytes >= 1) {
+ schedstatBuf[bytes - 1] = '\0'; /* remove trailing newline */
+ }
+ }
+
+ /* show what we got */
+ dvmPrintDebugMessage(target,
+ " | schedstat=( %s ) utm=%lu stm=%lu core=%d\n",
+ schedstatBuf, procStatData.utime, procStatData.stime,
+ procStatData.processor);
+#endif
+}
+
+struct SchedulerStats {
+ int policy;
+ int priority;
+ char group[32];
+};
+
+/*
+ * Get scheduler statistics.
+ */
+static void getSchedulerStats(SchedulerStats* stats, pid_t tid) {
+ struct sched_param sp;
+ if (pthread_getschedparam(pthread_self(), &stats->policy, &sp) != 0) {
+ ALOGW("Warning: pthread_getschedparam failed");
+ stats->policy = -1;
+ stats->priority = -1;
+ } else {
+ stats->priority = sp.sched_priority;
+ }
+ if (getSchedulerGroup(tid, stats->group, sizeof(stats->group)) == 0 &&
+ stats->group[0] == '\0') {
+ strcpy(stats->group, "default");
+ }
+}
+
/*
* Print information about the specified thread.
*
@@ -3222,12 +3281,8 @@ void dvmDumpThreadEx(const DebugOutputTarget* target, Thread* thread,
StringObject* nameStr;
char* threadName = NULL;
char* groupName = NULL;
- char schedulerGroupBuf[32];
bool isDaemon;
int priority; // java.lang.Thread priority
- int policy; // pthread policy
- struct sched_param sp; // pthread scheduling parameters
- char schedstatBuf[64]; // contents of /proc/[pid]/task/[tid]/schedstat
/*
* Get the java.lang.Thread object. This function gets called from
@@ -3242,7 +3297,7 @@ void dvmDumpThreadEx(const DebugOutputTarget* target, Thread* thread,
*/
threadObj = thread->threadObj;
if (threadObj == NULL) {
- LOGI("Can't dump thread %d: threadObj not set", thread->threadId);
+ ALOGI("Can't dump thread %d: threadObj not set", thread->threadId);
return;
}
dvmAddTrackedAlloc(threadObj, NULL);
@@ -3254,17 +3309,6 @@ void dvmDumpThreadEx(const DebugOutputTarget* target, Thread* thread,
priority = dvmGetFieldInt(threadObj, gDvm.offJavaLangThread_priority);
isDaemon = dvmGetFieldBoolean(threadObj, gDvm.offJavaLangThread_daemon);
- if (pthread_getschedparam(pthread_self(), &policy, &sp) != 0) {
- LOGW("Warning: pthread_getschedparam failed");
- policy = -1;
- sp.sched_priority = -1;
- }
- if (getSchedulerGroup(thread->systemTid, schedulerGroupBuf,
- sizeof(schedulerGroupBuf)) == 0 &&
- schedulerGroupBuf[0] == '\0') {
- strcpy(schedulerGroupBuf, "default");
- }
-
/* a null value for group is not expected, but deal with it anyway */
groupObj = (Object*) dvmGetFieldObject(threadObj,
gDvm.offJavaLangThread_group);
@@ -3276,6 +3320,9 @@ void dvmDumpThreadEx(const DebugOutputTarget* target, Thread* thread,
if (groupName == NULL)
groupName = strdup("(null; initializing?)");
+ SchedulerStats schedStats;
+ getSchedulerStats(&schedStats, thread->systemTid);
+
dvmPrintDebugMessage(target,
"\"%s\"%s prio=%d tid=%d %s%s\n",
threadName, isDaemon ? " daemon" : "",
@@ -3293,40 +3340,22 @@ void dvmDumpThreadEx(const DebugOutputTarget* target, Thread* thread,
dvmPrintDebugMessage(target,
" | sysTid=%d nice=%d sched=%d/%d cgrp=%s handle=%d\n",
thread->systemTid, getpriority(PRIO_PROCESS, thread->systemTid),
- policy, sp.sched_priority, schedulerGroupBuf, (int)thread->handle);
+ schedStats.policy, schedStats.priority, schedStats.group, (int)thread->handle);
- /* get some bits from /proc/self/stat */
- ProcStatData procStatData;
- if (!dvmGetThreadStats(&procStatData, thread->systemTid)) {
- /* failed, use zeroed values */
- memset(&procStatData, 0, sizeof(procStatData));
- }
+ dumpSchedStat(target, thread->systemTid);
- /* grab the scheduler stats for this thread */
- snprintf(schedstatBuf, sizeof(schedstatBuf), "/proc/self/task/%d/schedstat",
- thread->systemTid);
- int schedstatFd = open(schedstatBuf, O_RDONLY);
- strcpy(schedstatBuf, "0 0 0"); /* show this if open/read fails */
- if (schedstatFd >= 0) {
- ssize_t bytes;
- bytes = read(schedstatFd, schedstatBuf, sizeof(schedstatBuf) - 1);
- close(schedstatFd);
- if (bytes >= 1) {
- schedstatBuf[bytes-1] = '\0'; /* remove trailing newline */
- }
+ /* grab the native stack, if possible */
+ if (thread->status == THREAD_NATIVE || thread->status == THREAD_VMWAIT) {
+ dvmDumpNativeStack(target, thread->systemTid);
}
- /* show what we got */
- dvmPrintDebugMessage(target,
- " | schedstat=( %s ) utm=%lu stm=%lu core=%d\n",
- schedstatBuf, procStatData.utime, procStatData.stime,
- procStatData.processor);
-
if (isRunning)
dvmDumpRunningThreadStack(target, thread);
else
dvmDumpThreadStack(target, thread);
+ dvmPrintDebugMessage(target, "\n");
+
dvmReleaseTrackedAlloc(threadObj, NULL);
free(threadName);
free(groupName);
@@ -3334,7 +3363,7 @@ void dvmDumpThreadEx(const DebugOutputTarget* target, Thread* thread,
std::string dvmGetThreadName(Thread* thread) {
if (thread->threadObj == NULL) {
- LOGW("threadObj is NULL, name not available");
+ ALOGW("threadObj is NULL, name not available");
return "-unknown-";
}
@@ -3346,6 +3375,59 @@ std::string dvmGetThreadName(Thread* thread) {
return result;
}
+#ifdef HAVE_ANDROID_OS
+/*
+ * Dumps information about a non-Dalvik thread.
+ */
+static void dumpNativeThread(const DebugOutputTarget* target, pid_t tid) {
+ char path[64];
+ snprintf(path, sizeof(path), "/proc/%d/comm", tid);
+
+ int fd = open(path, O_RDONLY);
+ char name[64];
+ ssize_t n = 0;
+ if (fd >= 0) {
+ n = read(fd, name, sizeof(name) - 1);
+ close(fd);
+ }
+ if (n > 0 && name[n - 1] == '\n') {
+ n -= 1;
+ }
+ if (n <= 0) {
+ strcpy(name, "<no name>");
+ } else {
+ name[n] = '\0';
+ }
+
+ SchedulerStats schedStats;
+ getSchedulerStats(&schedStats, tid);
+
+ dvmPrintDebugMessage(target,
+ "\"%s\" sysTid=%d nice=%d sched=%d/%d cgrp=%s\n",
+ name, tid, getpriority(PRIO_PROCESS, tid),
+ schedStats.policy, schedStats.priority, schedStats.group);
+ dumpSchedStat(target, tid);
+ // Temporarily disabled collecting native stacks from non-Dalvik
+ // threads because sometimes they misbehave.
+ //dvmDumpNativeStack(target, tid);
+
+ dvmPrintDebugMessage(target, "\n");
+}
+
+/*
+ * Returns true if the specified tid is a Dalvik thread.
+ * Assumes the thread list lock is held.
+ */
+static bool isDalvikThread(pid_t tid) {
+ for (Thread* thread = gDvm.threadList; thread != NULL; thread = thread->next) {
+ if (thread->systemTid == tid) {
+ return true;
+ }
+ }
+ return false;
+}
+#endif
+
/*
* Dump all threads to the log file -- just calls dvmDumpAllThreadsEx() with
* an output target.
@@ -3373,7 +3455,7 @@ void dvmDumpAllThreadsEx(const DebugOutputTarget* target, bool grabLock)
#ifdef HAVE_ANDROID_OS
dvmPrintDebugMessage(target,
- "(mutexes: tll=%x tsl=%x tscl=%x ghl=%x)\n",
+ "(mutexes: tll=%x tsl=%x tscl=%x ghl=%x)\n\n",
gDvm.threadListLock.value,
gDvm._threadSuspendLock.value,
gDvm.threadSuspendCountLock.value,
@@ -3393,6 +3475,30 @@ void dvmDumpAllThreadsEx(const DebugOutputTarget* target, bool grabLock)
thread = thread->next;
}
+#ifdef HAVE_ANDROID_OS
+ char path[64];
+ snprintf(path, sizeof(path), "/proc/%d/task", getpid());
+
+ DIR* d = opendir(path);
+ if (d) {
+ dirent de;
+ dirent* result;
+ bool first = true;
+ while (!readdir_r(d, &de, &result) && result) {
+ char* end;
+ pid_t tid = strtol(de.d_name, &end, 10);
+ if (!*end && !isDalvikThread(tid)) {
+ if (first) {
+ dvmPrintDebugMessage(target, "NATIVE THREADS:\n");
+ first = false;
+ }
+ dumpNativeThread(target, tid);
+ }
+ }
+ closedir(d);
+ }
+#endif
+
if (grabLock)
dvmUnlockThreadList();
}
@@ -3434,7 +3540,6 @@ void dvmNukeThread(Thread* thread)
* The target thread can continue to execute between the two signals.
* (The first just causes debuggerd to attach to it.)
*/
-
#ifdef SIGSTKFLT
#define SIG SIGSTKFLT
#define SIGNAME "SIGSTKFLT"
@@ -3445,22 +3550,22 @@ void dvmNukeThread(Thread* thread)
#error No signal available for dvmNukeThread
#endif
- LOGD("threadid=%d: sending two " SIGNAME "s to threadid=%d (tid=%d) to"
- " cause debuggerd dump",
- dvmThreadSelf()->threadId, thread->threadId, thread->systemTid);
+ ALOGD("threadid=%d: sending two " SIGNAME "s to threadid=%d (tid=%d) to"
+ " cause debuggerd dump",
+ dvmThreadSelf()->threadId, thread->threadId, thread->systemTid);
killResult = pthread_kill(thread->handle, SIG);
if (killResult != 0) {
- LOGD("NOTE: pthread_kill #1 failed: %s", strerror(killResult));
+ ALOGD("NOTE: pthread_kill #1 failed: %s", strerror(killResult));
}
usleep(2 * 1000 * 1000); // TODO: timed-wait until debuggerd attaches
killResult = pthread_kill(thread->handle, SIG);
if (killResult != 0) {
- LOGD("NOTE: pthread_kill #2 failed: %s", strerror(killResult));
+ ALOGD("NOTE: pthread_kill #2 failed: %s", strerror(killResult));
}
- LOGD("Sent, pausing to let debuggerd run");
+ 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 */
signal(SIGSEGV, SIG_IGN);
- LOGD("Continuing");
+ ALOGD("Continuing");
}