diff options
| author | Bob Lee <crazybob@crazybob.org> | 2009-09-16 10:23:01 -0700 |
|---|---|---|
| committer | Bob Lee <crazybob@crazybob.org> | 2009-09-16 10:23:01 -0700 |
| commit | f56201c2c2ff6e2c9f22cc0b5e98dec7a55804eb (patch) | |
| tree | 5fb6f9bbef0c2f68ebf4c65f178b9516e3f3177a | |
| parent | f6a6f20adbb2b23a30508df18136d0ef064c72bb (diff) | |
| parent | 3eae287ea5c8df8674059716d4cea6ed713b7fe0 (diff) | |
| download | android_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.java | 33 | ||||
| -rw-r--r-- | vm/Dvm.mk | 1 | ||||
| -rw-r--r-- | vm/Thread.c | 117 | ||||
| -rw-r--r-- | vm/Thread.h | 21 | ||||
| -rw-r--r-- | vm/native/SystemThread.c | 169 | ||||
| -rw-r--r-- | vm/native/SystemThread.h | 41 | ||||
| -rw-r--r-- | vm/native/dalvik_system_SamplingProfiler.c | 7 |
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 */ } } @@ -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 +}; |
