Improve "waiting on"/"waiting to lock" SIGQUIT dump info.
In particular, when we're waiting on a Class, say which class:
I(16573) - waiting on <0xf5ed54f8> (java.lang.Class<java.lang.ref.ReferenceQueue>)
versus:
I(16573) - waiting on <0xf5feda38> (a java.util.LinkedList)
Bug: http://code.google.com/p/android/issues/detail?id=17349
Change-Id: I844d02c008b1499adb02995ff3da25ba8cad0e0a
diff --git a/vm/Misc.cpp b/vm/Misc.cpp
index 627c4e2..3b1179e 100644
--- a/vm/Misc.cpp
+++ b/vm/Misc.cpp
@@ -715,3 +715,58 @@
return NULL;
}
+
+// From RE2.
+static void StringAppendV(std::string* dst, const char* format, va_list ap) {
+ // First try with a small fixed size buffer
+ char space[1024];
+
+ // It's possible for methods that use a va_list to invalidate
+ // the data in it upon use. The fix is to make a copy
+ // of the structure before using it and use that copy instead.
+ va_list backup_ap;
+ va_copy(backup_ap, ap);
+ int result = vsnprintf(space, sizeof(space), format, backup_ap);
+ va_end(backup_ap);
+
+ if ((result >= 0) && ((size_t) result < sizeof(space))) {
+ // It fit
+ dst->append(space, result);
+ return;
+ }
+
+ // Repeatedly increase buffer size until it fits
+ int length = sizeof(space);
+ while (true) {
+ if (result < 0) {
+ // Older behavior: just try doubling the buffer size
+ length *= 2;
+ } else {
+ // We need exactly "result+1" characters
+ length = result+1;
+ }
+ char* buf = new char[length];
+
+ // Restore the va_list before we use it again
+ va_copy(backup_ap, ap);
+ result = vsnprintf(buf, length, format, backup_ap);
+ va_end(backup_ap);
+
+ if ((result >= 0) && (result < length)) {
+ // It fit
+ dst->append(buf, result);
+ delete[] buf;
+ return;
+ }
+ delete[] buf;
+ }
+}
+
+std::string dvmStringPrintf(const char* fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ std::string result;
+ StringAppendV(&result, fmt, ap);
+ va_end(ap);
+ return result;
+}
diff --git a/vm/Misc.h b/vm/Misc.h
index aabddfb..017548d 100644
--- a/vm/Misc.h
+++ b/vm/Misc.h
@@ -22,6 +22,7 @@
#include <string>
+#include <stdarg.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
@@ -303,4 +304,9 @@
*/
const char* dvmPathToAbsolutePortion(const char* path);
+/**
+ * Returns a string corresponding to printf-like formatting of the arguments.
+ */
+std::string dvmStringPrintf(const char* fmt, ...) __attribute__((__format__ (__printf__, 1, 2)));
+
#endif /*_DALVIK_MISC*/
diff --git a/vm/Profile.cpp b/vm/Profile.cpp
index f7240ce..f3f73a8 100644
--- a/vm/Profile.cpp
+++ b/vm/Profile.cpp
@@ -249,16 +249,11 @@
/*
* Dump the thread list to the specified file.
*/
-static void dumpThreadList(FILE* fp)
-{
- Thread* thread;
-
+static void dumpThreadList(FILE* fp) {
dvmLockThreadList(NULL);
- for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
- char* name = dvmGetThreadName(thread);
-
- fprintf(fp, "%d\t%s\n", thread->threadId, name);
- free(name);
+ for (Thread* thread = gDvm.threadList; thread != NULL; thread = thread->next) {
+ std::string threadName(dvmGetThreadName(thread));
+ fprintf(fp, "%d\t%s\n", thread->threadId, threadName.c_str());
}
dvmUnlockThreadList();
}
diff --git a/vm/Sync.cpp b/vm/Sync.cpp
index 8257f80..09b12e4 100644
--- a/vm/Sync.cpp
+++ b/vm/Sync.cpp
@@ -271,7 +271,7 @@
u4 relativePc;
char eventBuffer[174];
const char *fileName;
- char procName[33], *selfName;
+ char procName[33];
char *cp;
size_t len;
int fd;
@@ -299,9 +299,8 @@
cp = logWriteInt(cp, isSensitive);
/* Emit self thread name string, <= 37 bytes. */
- selfName = dvmGetThreadName(self);
- cp = logWriteString(cp, selfName, strlen(selfName));
- free(selfName);
+ std::string selfName = dvmGetThreadName(self);
+ cp = logWriteString(cp, selfName.c_str(), selfName.size());
/* Emit the wait time, 5 bytes. */
cp = logWriteInt(cp, waitMs);
diff --git a/vm/Thread.cpp b/vm/Thread.cpp
index 4947316..bef4bc6 100644
--- a/vm/Thread.cpp
+++ b/vm/Thread.cpp
@@ -554,10 +554,9 @@
threadId, target->threadId);
}
- char* threadName = dvmGetThreadName(target);
+ std::string threadName(dvmGetThreadName(target));
LOGV("threadid=%d: suspending daemon id=%d name='%s'",
- threadId, target->threadId, threadName);
- free(threadName);
+ threadId, target->threadId, threadName.c_str());
/* mark as suspended */
lockThreadSuspendCount();
@@ -1455,9 +1454,8 @@
{
Thread* self = (Thread*) arg;
- char *threadName = dvmGetThreadName(self);
- setThreadName(threadName);
- free(threadName);
+ std::string threadName(dvmGetThreadName(self));
+ setThreadName(threadName.c_str());
/*
* Finish initializing the Thread struct.
@@ -3121,13 +3119,11 @@
}
if (setpriority(PRIO_PROCESS, pid, newNice) != 0) {
- char* str = dvmGetThreadName(thread);
+ std::string threadName(dvmGetThreadName(thread));
LOGI("setPriority(%d) '%s' to prio=%d(n=%d) failed: %s",
- pid, str, newPriority, newNice, strerror(errno));
- free(str);
+ pid, threadName.c_str(), newPriority, newNice, strerror(errno));
} else {
- LOGV("setPriority(%d) to prio=%d(n=%d)",
- pid, newPriority, newNice);
+ LOGV("setPriority(%d) to prio=%d(n=%d)", pid, newPriority, newNice);
}
}
@@ -3414,24 +3410,13 @@
free(groupName);
}
-/*
- * Get the name of a thread.
- *
- * For correctness, the caller should hold the thread list lock to ensure
- * that the thread doesn't go away mid-call.
- *
- * Returns a newly-allocated string, or NULL if the Thread doesn't have a name.
- */
-char* dvmGetThreadName(Thread* thread)
-{
- StringObject* nameObj;
-
+std::string dvmGetThreadName(Thread* thread) {
if (thread->threadObj == NULL) {
LOGW("threadObj is NULL, name not available");
- return strdup("-unknown-");
+ return "-unknown-";
}
- nameObj = (StringObject*)
+ StringObject* nameObj = (StringObject*)
dvmGetFieldObject(thread->threadObj, gDvm.offJavaLangThread_name);
return dvmCreateCstrFromString(nameObj);
}
diff --git a/vm/Thread.h b/vm/Thread.h
index a4c64ec..b4c866e 100644
--- a/vm/Thread.h
+++ b/vm/Thread.h
@@ -532,9 +532,12 @@
void dvmThreadSleep(u8 msec, u4 nsec);
/*
- * Get the name of a thread. (For safety, hold the thread list lock.)
+ * Get the name of a thread.
+ *
+ * For correctness, the caller should hold the thread list lock to ensure
+ * that the thread doesn't go away mid-call.
*/
-char* dvmGetThreadName(Thread* thread);
+std::string dvmGetThreadName(Thread* thread);
/*
* Convert ThreadStatus to a string.
diff --git a/vm/interp/Stack.cpp b/vm/interp/Stack.cpp
index bbce741..3c0d9da 100644
--- a/vm/interp/Stack.cpp
+++ b/vm/interp/Stack.cpp
@@ -1156,6 +1156,28 @@
return true;
}
+static void printWaitMessage(const DebugOutputTarget* target, const char* detail, Object* obj,
+ Thread* thread)
+{
+ std::string msg(dvmStringPrintf(" - waiting %s <%p> ", detail, obj));
+
+ if (obj->clazz != gDvm.classJavaLangClass) {
+ // I(16573) - waiting on <0xf5feda38> (a java.util.LinkedList)
+ msg += "(a " + dvmHumanReadableDescriptor(obj->clazz->descriptor) + ")";
+ } else {
+ // I(16573) - waiting on <0xf5ed54f8> (java.lang.Class<java.lang.ref.ReferenceQueue>)
+ ClassObject* clazz = reinterpret_cast<ClassObject*>(obj);
+ msg += "(java.lang.Class<" + dvmHumanReadableDescriptor(clazz->descriptor) + ">)";
+ }
+
+ if (thread != NULL) {
+ std::string threadName(dvmGetThreadName(thread));
+ msg += dvmStringPrintf(" held by tid=%d (%s)", thread->threadId, threadName.c_str());
+ }
+
+ dvmPrintDebugMessage(target, "%s\n", msg.c_str());
+}
+
/*
* Dump stack frames, starting from the specified frame and moving down.
*
@@ -1234,35 +1256,16 @@
Object* obj = dvmGetMonitorObject(mon);
if (obj != NULL) {
Thread* joinThread = NULL;
- std::string className(dvmHumanReadableDescriptor(obj->clazz->descriptor));
- if (className == "java.lang.VMThread") {
+ if (obj->clazz == gDvm.classJavaLangVMThread) {
joinThread = dvmGetThreadFromThreadObject(obj);
}
- if (joinThread == NULL) {
- dvmPrintDebugMessage(target,
- " - waiting on <%p> (a %s)\n", obj, className.c_str());
- } else {
- dvmPrintDebugMessage(target,
- " - waiting on <%p> (a %s) tid=%d\n", obj, className.c_str(),
- joinThread->threadId);
- }
+ printWaitMessage(target, "on", obj, joinThread);
}
} else if (thread->status == THREAD_MONITOR) {
Object* obj;
Thread* owner;
if (extractMonitorEnterObject(thread, &obj, &owner)) {
- std::string className(dvmHumanReadableDescriptor(obj->clazz->descriptor));
- if (owner != NULL) {
- char* threadName = dvmGetThreadName(owner);
- dvmPrintDebugMessage(target,
- " - waiting to lock <%p> (a %s) held by threadid=%d (%s)\n",
- obj, className.c_str(), owner->threadId, threadName);
- free(threadName);
- } else {
- dvmPrintDebugMessage(target,
- " - waiting to lock <%p> (a %s) held by ???\n",
- obj, className.c_str());
- }
+ printWaitMessage(target, "to lock", obj, owner);
}
}
}