summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBob Lee <crazybob@crazybob.org>2009-09-16 10:23:01 -0700
committerBob Lee <crazybob@crazybob.org>2009-09-16 10:23:01 -0700
commitf56201c2c2ff6e2c9f22cc0b5e98dec7a55804eb (patch)
tree5fb6f9bbef0c2f68ebf4c65f178b9516e3f3177a
parentf6a6f20adbb2b23a30508df18136d0ef064c72bb (diff)
parent3eae287ea5c8df8674059716d4cea6ed713b7fe0 (diff)
downloadandroid_dalvik-f56201c2c2ff6e2c9f22cc0b5e98dec7a55804eb.tar.gz
android_dalvik-f56201c2c2ff6e2c9f22cc0b5e98dec7a55804eb.tar.bz2
android_dalvik-f56201c2c2ff6e2c9f22cc0b5e98dec7a55804eb.zip
resolved conflicts for merge of 3eae287e to master
-rw-r--r--libcore/dalvik/src/main/java/dalvik/system/SamplingProfiler.java33
-rw-r--r--vm/Dvm.mk1
-rw-r--r--vm/Thread.c117
-rw-r--r--vm/Thread.h21
-rw-r--r--vm/native/SystemThread.c169
-rw-r--r--vm/native/SystemThread.h41
-rw-r--r--vm/native/dalvik_system_SamplingProfiler.c7
7 files changed, 252 insertions, 137 deletions
diff --git a/libcore/dalvik/src/main/java/dalvik/system/SamplingProfiler.java b/libcore/dalvik/src/main/java/dalvik/system/SamplingProfiler.java
index 65e56f27f..1d88dd170 100644
--- a/libcore/dalvik/src/main/java/dalvik/system/SamplingProfiler.java
+++ b/libcore/dalvik/src/main/java/dalvik/system/SamplingProfiler.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package dalvik.system;
import java.util.logging.Logger;
@@ -114,6 +130,10 @@ public class SamplingProfiler {
byte[] bytes = snapshot(pointer);
long elapsed = System.nanoTime() - start;
+ /*
+ * We shifted the times by 10 bits in the sampling thread to avoid
+ * overflow. Undo the shift and then convert from ns to us.
+ */
long averageSampleTime = ((totalSampleTime / totalThreadsSampled)
<< 10) / 1000;
logger.info("Grabbed snapshot in " + (elapsed / 1000) + "us."
@@ -159,6 +179,8 @@ public class SamplingProfiler {
* will recreate the thread the next time {@link #start(int)} is called.
*
* @throws IllegalStateException if the profiler is already shutting down
+ * or if it hasn't started yet
+ *
*/
public void shutDown() {
Thread toStop;
@@ -167,8 +189,8 @@ public class SamplingProfiler {
toStop = samplingThread;
if (toStop == null) {
- // The profiler hasn't started yet.
- return;
+ throw new IllegalStateException(
+ "The profiler was never started.");
}
state = State.SHUTTING_DOWN;
@@ -177,11 +199,12 @@ public class SamplingProfiler {
}
// Release lock to 'this' so background thread can grab it and stop.
- boolean successful = false;
- while (!successful) {
+ // Interrupt the thread in case it's sleeping.
+ toStop.interrupt();
+ while (true) {
try {
toStop.join();
- successful = true;
+ break;
} catch (InterruptedException e) { /* ignore */ }
}
diff --git a/vm/Dvm.mk b/vm/Dvm.mk
index 672d3d766..5aea24204 100644
--- a/vm/Dvm.mk
+++ b/vm/Dvm.mk
@@ -180,6 +180,7 @@ LOCAL_SRC_FILES := \
native/org_apache_harmony_dalvik_ddmc_DdmServer.c \
native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.c \
native/sun_misc_Unsafe.c \
+ native/SystemThread.c \
oo/AccessCheck.c \
oo/Array.c \
oo/Class.c \
diff --git a/vm/Thread.c b/vm/Thread.c
index 96b4b610a..52ff25018 100644
--- a/vm/Thread.c
+++ b/vm/Thread.c
@@ -18,6 +18,7 @@
* Thread support.
*/
#include "Dalvik.h"
+#include "native/SystemThread.h"
#include "utils/threads.h" // need Android thread priorities
@@ -2260,9 +2261,7 @@ void dvmDetachCurrentThread(void)
setThreadSelf(NULL);
- if (self->statFile > 0) {
- close(self->statFile);
- }
+ dvmDetachSystemThread(self);
freeThread(self);
}
@@ -3903,115 +3902,3 @@ void dvmGcScanRootThreadGroups()
*/
gcScanAllThreads();
}
-
-/* Converts a Linux thread state to a ThreadStatus. */
-static ThreadStatus stateToStatus(char state) {
- switch (state) {
- case 'R': return THREAD_RUNNING; // running
- case 'S': return THREAD_WAIT; // sleeping in interruptible wait
- case 'D': return THREAD_WAIT; // uninterruptible disk sleep
- case 'Z': return THREAD_ZOMBIE; // zombie
- case 'T': return THREAD_WAIT; // traced or stopped on a signal
- case 'W': return THREAD_PAGING; // paging memory
- default:
- LOGE("Unexpected state: %c", state);
- return THREAD_NATIVE;
- }
-}
-
-/* Reads the state char starting from the beginning of the file. */
-static char readStateFromBeginning(Thread* thread) {
- char buffer[256];
- int size = read(thread->statFile, buffer, sizeof(buffer));
- if (size == 0) {
- LOGE("EOF trying to read stat file.");
- return 0;
- }
- char* endOfName = (char*) memchr(buffer, ')', sizeof(buffer));
- if (endOfName == NULL) {
- LOGE("End of executable name not found.");
- return 0;
- }
- char* state = endOfName + 2;
- thread->stateOffset = state - buffer;
- if (*state == 0) {
- LOGE("State char is 0.");
- }
- return *state;
-}
-
-/*
- * Looks for the state char at the last place we found it. Read from the
- * beginning if necessary.
- */
-static char readStateRelatively(Thread* thread) {
- char buffer[3];
- // Position file offset at end of executable name.
- int result = lseek(thread->statFile, thread->stateOffset - 2, SEEK_SET);
- if (result < 0) {
- LOGE("lseek() error.");
- return 0;
- }
- int size = read(thread->statFile, buffer, sizeof(buffer));
- if (size < (int) sizeof(buffer)) {
- LOGE("EOF trying to read stat file.");
- return 0;
- }
- if (buffer[0] != ')') {
- // The executable name must have changed.
- result = lseek(thread->statFile, 0, SEEK_SET);
- if (result < 0) {
- LOGE("lseek() error.");
- return 0;
- }
- return readStateFromBeginning(thread);
- }
- char state = buffer[2];
- if (state == 0) {
- LOGE("State char is 0.");
- }
- return state;
-}
-
-ThreadStatus dvmGetNativeThreadStatus(Thread* thread) {
- // TODO: Add a custom hook so this just reads a char from memory.
-
- ThreadStatus status = thread->status;
- if (status != THREAD_NATIVE) {
- // Return cached status so we don't accidentally return THREAD_NATIVE.
- return status;
- }
-
- if (thread->statFile == -1) {
- // We tried and failed to open the file earlier. Return current status.
- return thread->status;
- }
-
- // Note: see "man proc" for the format of stat.
- char state;
- if (thread->statFile == 0) {
- // We haven't tried to open the file yet. Do so.
- char fileName[256];
- sprintf(fileName, "/proc/self/task/%d/stat", thread->systemTid);
- thread->statFile = open(fileName, O_RDONLY);
- if (thread->statFile == NULL) {
- LOGE("Error opening %s: %s", fileName, strerror(errno));
- thread->statFile = -1;
- return thread->status;
- }
- state = readStateFromBeginning(thread);
- } else {
- state = readStateRelatively(thread);
- }
-
- if (state == 0) {
- close(thread->statFile);
- thread->statFile = -1;
- return thread->status;
- }
- ThreadStatus nativeStatus = stateToStatus(state);
-
- // The thread status could have changed from NATIVE.
- status = thread->status;
- return status == THREAD_NATIVE ? nativeStatus : status;
-}
diff --git a/vm/Thread.h b/vm/Thread.h
index 1b01e08c2..e12088dfe 100644
--- a/vm/Thread.h
+++ b/vm/Thread.h
@@ -53,7 +53,6 @@ typedef enum ThreadStatus {
THREAD_STARTING = 6, /* started, not yet on thread list */
THREAD_NATIVE = 7, /* off in a JNI native method */
THREAD_VMWAIT = 8, /* waiting on a VM resource */
- THREAD_PAGING = 9, /* paging memory */
} ThreadStatus;
/* thread priorities, from java.lang.Thread */
@@ -81,6 +80,11 @@ void dvmSlayDaemons(void);
#define kMaxStackSize (256*1024 + STACK_OVERFLOW_RESERVE)
/*
+ * System thread state. See native/SystemThread.h.
+ */
+typedef struct SystemThread SystemThread;
+
+/*
* Our per-thread data.
*
* These are allocated on the system heap.
@@ -223,10 +227,8 @@ typedef struct Thread {
struct ShadowSpace* shadowSpace;
#endif
- /* /proc/PID/task/TID/stat */
- int statFile;
- /* offset of state char in stat file, last we checked */
- int stateOffset;
+ /* system thread state */
+ SystemThread* systemThread;
} Thread;
/* start point for an internal thread; mimics pthread args */
@@ -435,7 +437,6 @@ void dvmChangeThreadSchedulerPolicy(SchedPolicy policy);
*/
void dvmChangeThreadPriority(Thread* thread, int newPriority);
-
/*
* Debug: dump information about a single thread.
*/
@@ -449,14 +450,6 @@ void dvmDumpThreadEx(const DebugOutputTarget* target, Thread* thread,
void dvmDumpAllThreads(bool grabLock);
void dvmDumpAllThreadsEx(const DebugOutputTarget* target, bool grabLock);
-/*
- * Reads the native thread status. If the thread is in native code, this
- * function queries the native thread state and converts it to an equivalent
- * ThreadStatus. If the native status can't be read, this function returns
- * THREAD_NATIVE.
- */
-ThreadStatus dvmGetNativeThreadStatus(Thread* thread);
-
#ifdef WITH_MONITOR_TRACKING
/*
* Track locks held by the current thread, along with the stack trace at
diff --git a/vm/native/SystemThread.c b/vm/native/SystemThread.c
new file mode 100644
index 000000000..bd2be03e7
--- /dev/null
+++ b/vm/native/SystemThread.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SystemThread"
+
+/*
+ * System thread support.
+ */
+#include "Dalvik.h"
+#include "native/SystemThread.h"
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+struct SystemThread {
+ /*
+ * /proc/PID/task/TID/stat. -1 if not opened yet. -2 indicates an error
+ * occurred while opening the file.
+ */
+ int statFile;
+
+ /* Offset of state char in stat file, last we checked. */
+ int stateOffset;
+};
+
+void dvmDetachSystemThread(Thread* thread) {
+ if (thread->systemThread != NULL) {
+ if (thread->systemThread->statFile > -1) {
+ close(thread->systemThread->statFile);
+ }
+ free(thread->systemThread);
+ thread->systemThread = NULL;
+ }
+}
+
+/* Converts a Linux thread state to a ThreadStatus. */
+static ThreadStatus stateToStatus(char state) {
+ switch (state) {
+ case 'R': return THREAD_RUNNING; // running
+ case 'S': return THREAD_WAIT; // sleeping in interruptible wait
+ case 'D': return THREAD_WAIT; // uninterruptible disk sleep
+ case 'Z': return THREAD_ZOMBIE; // zombie
+ case 'T': return THREAD_WAIT; // traced or stopped on a signal
+ case 'W': return THREAD_WAIT; // paging memory
+ default:
+ LOGE("Unexpected state: %c", state);
+ return THREAD_NATIVE;
+ }
+}
+
+/* Reads the state char starting from the beginning of the file. */
+static char readStateFromBeginning(SystemThread* thread) {
+ char buffer[256];
+ int size = read(thread->statFile, buffer, sizeof(buffer) - 1);
+ if (size <= 0) {
+ LOGE("read() returned %d: %s", size, strerror(errno));
+ return 0;
+ }
+ char* endOfName = (char*) memchr(buffer, ')', size);
+ if (endOfName == NULL) {
+ LOGE("End of executable name not found.");
+ return 0;
+ }
+ char* state = endOfName + 2;
+ if ((state - buffer) + 1 > size) {
+ LOGE("Unexpected EOF while trying to read stat file.");
+ return 0;
+ }
+ thread->stateOffset = state - buffer;
+ return *state;
+}
+
+/*
+ * Looks for the state char at the last place we found it. Read from the
+ * beginning if necessary.
+ */
+static char readStateRelatively(SystemThread* thread) {
+ char buffer[3];
+ // Position file offset at end of executable name.
+ int result = lseek(thread->statFile, thread->stateOffset - 2, SEEK_SET);
+ if (result < 0) {
+ LOGE("lseek() error.");
+ return 0;
+ }
+ int size = read(thread->statFile, buffer, sizeof(buffer));
+ if (size < (int) sizeof(buffer)) {
+ LOGE("Unexpected EOF while trying to read stat file.");
+ return 0;
+ }
+ if (buffer[0] != ')') {
+ // The executable name must have changed.
+ result = lseek(thread->statFile, 0, SEEK_SET);
+ if (result < 0) {
+ LOGE("lseek() error.");
+ return 0;
+ }
+ return readStateFromBeginning(thread);
+ }
+ return buffer[2];
+}
+
+ThreadStatus dvmGetSystemThreadStatus(Thread* thread) {
+ ThreadStatus status = thread->status;
+ if (status != THREAD_NATIVE) {
+ // Return cached status so we don't accidentally return THREAD_NATIVE.
+ return status;
+ }
+
+ if (thread->systemThread == NULL) {
+ thread->systemThread = (SystemThread*) malloc(sizeof(SystemThread));
+ if (thread->systemThread == NULL) {
+ LOGE("Couldn't allocate a SystemThread.");
+ return THREAD_NATIVE;
+ }
+ thread->systemThread->statFile = -1;
+ }
+
+ SystemThread* systemThread = thread->systemThread;
+ if (systemThread->statFile == -2) {
+ // We tried and failed to open the file earlier. Return current status.
+ return thread->status;
+ }
+
+ // Note: see "man proc" for the format of stat.
+ // The format is "PID (EXECUTABLE NAME) STATE_CHAR ...".
+ // Example: "15 (/foo/bar) R ..."
+ char state;
+ if (systemThread->statFile == -1) {
+ // We haven't tried to open the file yet. Do so.
+ char fileName[256];
+ sprintf(fileName, "/proc/self/task/%d/stat", thread->systemTid);
+ systemThread->statFile = open(fileName, O_RDONLY);
+ if (systemThread->statFile == -1) {
+ LOGE("Error opening %s: %s", fileName, strerror(errno));
+ systemThread->statFile = -2;
+ return thread->status;
+ }
+ state = readStateFromBeginning(systemThread);
+ } else {
+ state = readStateRelatively(systemThread);
+ }
+
+ if (state == 0) {
+ close(systemThread->statFile);
+ systemThread->statFile = -2;
+ return thread->status;
+ }
+ ThreadStatus nativeStatus = stateToStatus(state);
+
+ // The thread status could have changed from NATIVE.
+ status = thread->status;
+ return status == THREAD_NATIVE ? nativeStatus : status;
+}
diff --git a/vm/native/SystemThread.h b/vm/native/SystemThread.h
new file mode 100644
index 000000000..fb41b04da
--- /dev/null
+++ b/vm/native/SystemThread.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * System thread support.
+ */
+#ifndef _DALVIK_SYSTEM_THREAD
+#define _DALVIK_SYSTEM_THREAD
+
+#include "Thread.h"
+
+/*
+ * Queries the system thread status for the given thread. If the thread is in
+ * native code, this function queries the system thread state and converts it
+ * to an equivalent ThreadStatus. If the system thread state is "paging",
+ * this function returns THREAD_WAIT. If the native status can't be read,
+ * this function returns THREAD_NATIVE. The thread list lock should be held
+ * when calling this function.
+ */
+ThreadStatus dvmGetSystemThreadStatus(Thread* thread);
+
+/*
+ * Frees system thread-specific state in the given thread. The thread list
+ * lock is *not* held when this function is invoked.
+ */
+void dvmDetachSystemThread(Thread* thread);
+
+#endif /*_DALVIK_SYSTEM_THREAD*/
diff --git a/vm/native/dalvik_system_SamplingProfiler.c b/vm/native/dalvik_system_SamplingProfiler.c
index 71ef49008..5642bde15 100644
--- a/vm/native/dalvik_system_SamplingProfiler.c
+++ b/vm/native/dalvik_system_SamplingProfiler.c
@@ -24,6 +24,7 @@
#include "Dalvik.h"
#include "native/InternalNativePriv.h"
+#include "native/SystemThread.h"
// ~20k
#define INITIAL_CAPACITY 1024
@@ -202,9 +203,9 @@ static void sample(SampleSet* set, Thread* thread) {
? EVENT_THREAD : OTHER_THREAD;
ThreadState threadState;
- switch (dvmGetNativeThreadStatus(thread)) {
+ switch (dvmGetSystemThreadStatus(thread)) {
case THREAD_RUNNING: threadState = RUNNING_THREAD; break;
- case THREAD_NATIVE: dvmAbort();
+ case THREAD_NATIVE: return; // Something went wrong. Skip this thread.
default: threadState = SUSPENDED_THREAD; // includes PAGING
}
@@ -643,4 +644,4 @@ const DalvikNativeMethod dvm_dalvik_system_SamplingProfiler[] = {
{ "setEventThread", "(ILjava/lang/Thread;)V",
Dalvik_dalvik_system_SamplingProfiler_setEventThread },
{ NULL, NULL, NULL },
-}; \ No newline at end of file
+};