summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build/Android.common.mk6
-rw-r--r--src/class_linker.cc3
-rw-r--r--src/class_linker.h4
-rw-r--r--src/dalvik_system_VMStack.cc65
-rw-r--r--src/heap.cc18
-rw-r--r--src/intern_table.cc13
-rw-r--r--src/intern_table.h4
-rw-r--r--src/java_lang_Thread.cc128
-rw-r--r--src/jni_internal.cc22
-rw-r--r--src/jni_internal.h10
-rw-r--r--src/logging.cc4
-rw-r--r--src/logging.h12
-rw-r--r--src/mutex.cc105
-rw-r--r--src/mutex.h87
-rw-r--r--src/runtime.cc12
-rw-r--r--src/runtime.h2
-rw-r--r--src/signal_catcher.cc7
-rw-r--r--src/signal_catcher.h5
-rw-r--r--src/thread.cc190
-rw-r--r--src/thread.h169
-rw-r--r--src/thread_android.cc91
-rw-r--r--src/thread_linux.cc29
-rw-r--r--src/thread_list.cc107
-rw-r--r--src/thread_list.h88
-rw-r--r--src/utils.cc9
-rw-r--r--src/utils.h3
26 files changed, 825 insertions, 368 deletions
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 3c203d4..f248029 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -64,6 +64,7 @@ LIBART_COMMON_SRC_FILES := \
src/compiler/codegen/arm/Assemble.cc \
src/compiler/codegen/arm/LocalOptimizations.cc \
src/compiler/codegen/arm/armv7-a/Codegen.cc \
+ src/dalvik_system_VMStack.cc \
src/dex_cache.cc \
src/dex_file.cc \
src/dex_instruction.cc \
@@ -79,6 +80,7 @@ LIBART_COMMON_SRC_FILES := \
src/java_lang_Runtime.cc \
src/java_lang_String.cc \
src/java_lang_System.cc \
+ src/java_lang_Thread.cc \
src/java_lang_Throwable.cc \
src/java_util_concurrent_atomic_AtomicLong.cc \
src/jni_compiler.cc \
@@ -92,6 +94,7 @@ LIBART_COMMON_SRC_FILES := \
src/managed_register_x86.cc \
src/memory_region.cc \
src/mspace.c \
+ src/mutex.cc \
src/object.cc \
src/object_bitmap.cc \
src/offsets.cc \
@@ -103,6 +106,7 @@ LIBART_COMMON_SRC_FILES := \
src/stringpiece.cc \
src/stringprintf.cc \
src/thread.cc \
+ src/thread_list.cc \
src/utf.cc \
src/utils.cc \
src/zip_archive.cc \
@@ -112,12 +116,14 @@ LIBART_TARGET_SRC_FILES := \
$(LIBART_COMMON_SRC_FILES) \
src/logging_android.cc \
src/runtime_android.cc \
+ src/thread_android.cc \
src/thread_arm.cc
LIBART_HOST_SRC_FILES := \
$(LIBART_COMMON_SRC_FILES) \
src/logging_linux.cc \
src/runtime_linux.cc \
+ src/thread_linux.cc \
src/thread_x86.cc
LIBARTTEST_COMMON_SRC_FILES := \
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 8595bfc..a8281a3 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -71,7 +71,7 @@ ClassLinker* ClassLinker::Create(const std::vector<const DexFile*>& boot_class_p
}
ClassLinker::ClassLinker(InternTable* intern_table)
- : classes_lock_(Mutex::Create("ClassLinker::Lock")),
+ : classes_lock_("ClassLinker lock"),
class_roots_(NULL),
array_interfaces_(NULL),
array_iftable_(NULL),
@@ -514,7 +514,6 @@ void ClassLinker::VisitRoots(Heap::RootVisitor* visitor, void* arg) const {
}
ClassLinker::~ClassLinker() {
- delete classes_lock_;
String::ResetClass();
Field::ResetClass();
Method::ResetClass();
diff --git a/src/class_linker.h b/src/class_linker.h
index e9606a7..fa0c789 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -10,8 +10,8 @@
#include "dex_file.h"
#include "heap.h"
#include "macros.h"
+#include "mutex.h"
#include "object.h"
-#include "thread.h"
#include "unordered_map.h"
#include "unordered_set.h"
@@ -264,9 +264,9 @@ class ClassLinker {
// multimap from a StringPiece hash code of a class descriptor to
// Class* instances. Results should be compared for a matching
// Class::descriptor_ and Class::class_loader_.
+ mutable Mutex classes_lock_;
typedef std::tr1::unordered_multimap<size_t, Class*> Table;
Table classes_;
- Mutex* classes_lock_;
// indexes into class_roots_.
// needs to be kept in sync with class_roots_descriptors_.
diff --git a/src/dalvik_system_VMStack.cc b/src/dalvik_system_VMStack.cc
new file mode 100644
index 0000000..2a3f18b
--- /dev/null
+++ b/src/dalvik_system_VMStack.cc
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#include "jni_internal.h"
+#include "object.h"
+
+#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
+
+namespace art {
+
+namespace {
+
+jint VMStack_fillStackTraceElements(JNIEnv* env, jclass, jobject targetThread, jobjectArray javaSteArray) {
+ UNIMPLEMENTED(FATAL);
+ return 0;
+}
+
+jobject VMStack_getCallingClassLoader(JNIEnv* env, jclass) {
+ UNIMPLEMENTED(WARNING);
+ return NULL;
+}
+
+jobjectArray VMStack_getClasses(JNIEnv* env, jclass, jint maxDepth) {
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+}
+
+jclass VMStack_getStackClass2(JNIEnv* env, jclass) {
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+}
+
+jobjectArray VMStack_getThreadStackTrace(JNIEnv* env, jclass, jobject targetThread) {
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+}
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(VMStack, fillStackTraceElements, "(Ljava/lang/Thread;[Ljava/lang/StackTraceElement;)I"),
+ NATIVE_METHOD(VMStack, getCallingClassLoader, "()Ljava/lang/ClassLoader;"),
+ NATIVE_METHOD(VMStack, getClasses, "(I)[Ljava/lang/Class;"),
+ NATIVE_METHOD(VMStack, getStackClass2, "()Ljava/lang/Class;"),
+ NATIVE_METHOD(VMStack, getThreadStackTrace, "(Ljava/lang/Thread;)[Ljava/lang/StackTraceElement;"),
+};
+
+} // namespace
+
+void register_dalvik_system_VMStack(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "dalvik/system/VMStack", gMethods, NELEM(gMethods));
+}
+
+} // namespace art
diff --git a/src/heap.cc b/src/heap.cc
index 7f6b106..e346478 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -126,7 +126,7 @@ void Heap::Init(size_t initial_size, size_t maximum_size,
// It's still to early to take a lock because there are no threads yet,
// but we can create the heap lock now. We don't create it earlier to
// make it clear that you can't use locks during heap initialization.
- lock_ = Mutex::Create("Heap lock");
+ lock_ = new Mutex("Heap lock");
}
void Heap::Destroy() {
@@ -176,7 +176,7 @@ void Heap::VerifyObject(const Object* obj) {
#endif
void Heap::VerifyObjectLocked(const Object* obj) {
- DCHECK_LOCK_HELD(lock_);
+ lock_->AssertHeld();
if (obj != NULL && !verify_object_disabled_) {
if (!IsAligned(obj, kObjectAlignment)) {
LOG(FATAL) << "Object isn't aligned: " << obj;
@@ -224,7 +224,7 @@ void Heap::VerifyHeap() {
void Heap::RecordAllocationLocked(Space* space, const Object* obj) {
#ifndef NDEBUG
if (Runtime::Current()->IsStarted()) {
- DCHECK_LOCK_HELD(lock_);
+ lock_->AssertHeld();
}
#endif
size_t size = space->AllocationSize(obj);
@@ -235,7 +235,7 @@ void Heap::RecordAllocationLocked(Space* space, const Object* obj) {
}
void Heap::RecordFreeLocked(Space* space, const Object* obj) {
- DCHECK_LOCK_HELD(lock_);
+ lock_->AssertHeld();
size_t size = space->AllocationSize(obj);
DCHECK_NE(size, 0u);
if (size < num_bytes_allocated_) {
@@ -263,7 +263,7 @@ void Heap::RecordImageAllocations(Space* space) {
}
Object* Heap::AllocateLocked(size_t size) {
- DCHECK_LOCK_HELD(lock_);
+ lock_->AssertHeld();
DCHECK(alloc_space_ != NULL);
Space* space = alloc_space_;
Object* obj = AllocateLocked(space, size);
@@ -274,7 +274,7 @@ Object* Heap::AllocateLocked(size_t size) {
}
Object* Heap::AllocateLocked(Space* space, size_t size) {
- DCHECK_LOCK_HELD(lock_);
+ lock_->AssertHeld();
// Fail impossible allocations. TODO: collect soft references.
if (size > maximum_size_) {
@@ -365,7 +365,7 @@ void Heap::CollectGarbage() {
}
void Heap::CollectGarbageInternal() {
- DCHECK_LOCK_HELD(lock_);
+ lock_->AssertHeld();
// TODO: Suspend all threads
{
@@ -402,14 +402,14 @@ void Heap::CollectGarbageInternal() {
}
void Heap::WaitForConcurrentGcToComplete() {
- DCHECK_LOCK_HELD(lock_);
+ lock_->AssertHeld();
}
// Given the current contents of the active heap, increase the allowed
// heap footprint to match the target utilization ratio. This should
// only be called immediately after a full garbage collection.
void Heap::GrowForUtilization() {
- DCHECK_LOCK_HELD(lock_);
+ lock_->AssertHeld();
UNIMPLEMENTED(ERROR);
}
diff --git a/src/intern_table.cc b/src/intern_table.cc
index 8a4e87e..41c1b2a 100644
--- a/src/intern_table.cc
+++ b/src/intern_table.cc
@@ -7,12 +7,7 @@
namespace art {
-InternTable::InternTable() {
- intern_table_lock_ = Mutex::Create("InternTable::Lock");
-}
-
-InternTable::~InternTable() {
- delete intern_table_lock_;
+InternTable::InternTable() : intern_table_lock_("InternTable lock") {
}
size_t InternTable::Size() const {
@@ -30,7 +25,7 @@ void InternTable::VisitRoots(Heap::RootVisitor* visitor, void* arg) const {
}
const String* InternTable::Lookup(Table& table, const String* s, uint32_t hash_code) {
- // Requires the intern_table_lock_.
+ intern_table_lock_.AssertHeld();
typedef Table::const_iterator It; // TODO: C++0x auto
for (It it = table.find(hash_code), end = table.end(); it != end; ++it) {
const String* existing_string = it->second;
@@ -42,7 +37,7 @@ const String* InternTable::Lookup(Table& table, const String* s, uint32_t hash_c
}
const String* InternTable::Insert(Table& table, const String* s, uint32_t hash_code) {
- // Requires the intern_table_lock_.
+ intern_table_lock_.AssertHeld();
table.insert(std::make_pair(hash_code, s));
return s;
}
@@ -53,7 +48,7 @@ void InternTable::RegisterStrong(const String* s) {
}
void InternTable::Remove(Table& table, const String* s, uint32_t hash_code) {
- // Requires the intern_table_lock_.
+ intern_table_lock_.AssertHeld();
typedef Table::const_iterator It; // TODO: C++0x auto
for (It it = table.find(hash_code), end = table.end(); it != end; ++it) {
if (it->second == s) {
diff --git a/src/intern_table.h b/src/intern_table.h
index c9de228..fe84347 100644
--- a/src/intern_table.h
+++ b/src/intern_table.h
@@ -6,6 +6,7 @@
#include "unordered_map.h"
#include "heap.h"
+#include "mutex.h"
#include "object.h"
namespace art {
@@ -23,7 +24,6 @@ namespace art {
class InternTable {
public:
InternTable();
- ~InternTable();
// Interns a potentially new string in the 'strong' table. (See above.)
const String* InternStrong(int32_t utf16_length, const char* utf8_data);
@@ -59,9 +59,9 @@ class InternTable {
const String* Insert(Table& table, const String* s, uint32_t hash_code);
void Remove(Table& table, const String* s, uint32_t hash_code);
+ mutable Mutex intern_table_lock_;
Table strong_interns_;
Table weak_interns_;
- Mutex* intern_table_lock_;
};
} // namespace art
diff --git a/src/java_lang_Thread.cc b/src/java_lang_Thread.cc
new file mode 100644
index 0000000..44578ee
--- /dev/null
+++ b/src/java_lang_Thread.cc
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#include "jni_internal.h"
+#include "object.h"
+#include "thread.h"
+#include "thread_list.h"
+
+#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
+
+namespace art {
+
+namespace {
+
+jobject Thread_currentThread(JNIEnv* env, jclass) {
+ Object* peer = Decode<Object*>(env, Thread::Current()->GetPeer());
+ return AddLocalReference<jobject>(env, peer);
+}
+
+jboolean Thread_interrupted(JNIEnv* env, jclass) {
+ return Thread::Current()->Interrupted();
+}
+
+jboolean Thread_isInterrupted(JNIEnv* env, jobject javaThread) {
+ ThreadListLock lock;
+ Thread* thread = Thread::FromManagedThread(env, javaThread);
+ return thread->IsInterrupted();
+}
+
+void Thread_nativeCreate(JNIEnv* env, jclass, jobject javaThread, jlong stackSize) {
+ UNIMPLEMENTED(FATAL);
+ //Object* threadObj = dvmDecodeIndirectRef(env, javaThread);
+ //dvmCreateInterpThread(threadObj, (int) stackSize);
+}
+
+jint Thread_nativeGetStatus(JNIEnv* env, jobject javaThread) {
+ ThreadListLock lock;
+ Thread* thread = Thread::FromManagedThread(env, javaThread);
+ return static_cast<jint>(thread->GetState());
+}
+
+jboolean Thread_nativeHoldsLock(JNIEnv* env, jobject javaThread, jobject javaObject) {
+ ThreadListLock lock;
+ //Thread* thread = Thread::FromManagedThread(env, javaThread);
+ //Object* object = dvmDecodeIndirectRef(env, javaObject);
+ //if (object == NULL) {
+ //dvmThrowNullPointerException("object == null");
+ //return JNI_FALSE;
+ //}
+ //Thread* thread = Thread::FromManagedThread(env, javaThread);
+ //int result = dvmHoldsLock(thread, object);
+ //return result;
+ UNIMPLEMENTED(FATAL);
+ return JNI_FALSE;
+}
+
+void Thread_nativeInterrupt(JNIEnv* env, jobject javaThread) {
+ ThreadListLock lock;
+ UNIMPLEMENTED(FATAL);
+ //Thread* thread = Thread::FromManagedThread(env, javaThread);
+ //if (thread != NULL) {
+ //dvmThreadInterrupt(thread);
+ //}
+}
+
+void Thread_nativeSetName(JNIEnv* env, jobject javaThread, jstring javaName) {
+ ThreadListLock lock;
+ UNIMPLEMENTED(WARNING);
+ //Thread* thread = Thread::FromManagedThread(env, javaThread);
+ //StringObject* nameStr = (StringObject*) dvmDecodeIndirectRef(env, javaName);
+ //int threadId = (thread != NULL) ? thread->threadId : -1;
+ //dvmDdmSendThreadNameChange(threadId, nameStr);
+}
+
+/*
+ * Alter the priority of the specified thread. "newPriority" will range
+ * from Thread.MIN_PRIORITY to Thread.MAX_PRIORITY (1-10), with "normal"
+ * threads at Thread.NORM_PRIORITY (5).
+ */
+void Thread_nativeSetPriority(JNIEnv* env, jobject javaThread, jint newPriority) {
+ ThreadListLock lock;
+ Thread* thread = Thread::FromManagedThread(env, javaThread);
+ thread->SetNativePriority(newPriority);
+}
+
+/*
+ * Causes the thread to temporarily pause and allow other threads to execute.
+ *
+ * The exact behavior is poorly defined. Some discussion here:
+ * http://www.cs.umd.edu/~pugh/java/memoryModel/archive/0944.html
+ */
+void Thread_yield(JNIEnv*, jobject) {
+ sched_yield();
+}
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(Thread, currentThread, "()Ljava/lang/Thread;"),
+ NATIVE_METHOD(Thread, interrupted, "()Z"),
+ NATIVE_METHOD(Thread, isInterrupted, "()Z"),
+ NATIVE_METHOD(Thread, nativeCreate, "(Ljava/lang/Thread;J)V"),
+ NATIVE_METHOD(Thread, nativeGetStatus, "()I"),
+ NATIVE_METHOD(Thread, nativeHoldsLock, "(Ljava/lang/Object;)Z"),
+ NATIVE_METHOD(Thread, nativeInterrupt, "()V"),
+ NATIVE_METHOD(Thread, nativeSetName, "(Ljava/lang/String;)V"),
+ NATIVE_METHOD(Thread, nativeSetPriority, "(I)V"),
+ NATIVE_METHOD(Thread, yield, "()V"),
+};
+
+} // namespace
+
+void register_java_lang_Thread(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "java/lang/Thread", gMethods, NELEM(gMethods));
+}
+
+} // namespace art
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index c60dc24..83a147f 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -452,16 +452,12 @@ class SharedLibrary {
SharedLibrary(const std::string& path, void* handle, Object* class_loader)
: path_(path),
handle_(handle),
- jni_on_load_lock_(Mutex::Create("JNI_OnLoad lock")),
+ jni_on_load_lock_("JNI_OnLoad lock"),
jni_on_load_thread_id_(Thread::Current()->GetThinLockId()),
jni_on_load_result_(kPending) {
pthread_cond_init(&jni_on_load_cond_, NULL);
}
- ~SharedLibrary() {
- delete jni_on_load_lock_;
- }
-
Object* GetClassLoader() {
return class_loader_;
}
@@ -491,7 +487,7 @@ class SharedLibrary {
<< "JNI_OnLoad...]";
}
ScopedThreadStateChange tsc(self, Thread::kWaiting); // TODO: VMWAIT
- pthread_cond_wait(&jni_on_load_cond_, jni_on_load_lock_->GetImpl());
+ pthread_cond_wait(&jni_on_load_cond_, jni_on_load_lock_.GetImpl());
}
bool okay = (jni_on_load_result_ == kOkay);
@@ -532,7 +528,7 @@ class SharedLibrary {
Object* class_loader_;
// Guards remaining items.
- Mutex* jni_on_load_lock_;
+ Mutex jni_on_load_lock_;
// Wait for JNI_OnLoad in other thread.
pthread_cond_t jni_on_load_cond_;
// Recursive invocation guard.
@@ -2654,13 +2650,13 @@ JavaVMExt::JavaVMExt(Runtime* runtime, Runtime::ParsedOptions* options)
log_third_party_jni(options->IsVerbose("third-party-jni")),
trace(options->jni_trace_),
work_around_app_jni_bugs(false), // TODO: add a way to enable this
- pins_lock(Mutex::Create("JNI pin table lock")),
+ pins_lock("JNI pin table lock"),
pin_table("pin table", kPinTableInitialSize, kPinTableMaxSize),
- globals_lock(Mutex::Create("JNI global reference table lock")),
+ globals_lock("JNI global reference table lock"),
globals(kGlobalsInitial, kGlobalsMax, kGlobal),
- weak_globals_lock(Mutex::Create("JNI weak global reference table lock")),
+ weak_globals_lock("JNI weak global reference table lock"),
weak_globals(kWeakGlobalsInitial, kWeakGlobalsMax, kWeakGlobal),
- libraries_lock(Mutex::Create("JNI shared libraries map lock")),
+ libraries_lock("JNI shared libraries map lock"),
libraries(new Libraries) {
functions = unchecked_functions = &gInvokeInterface;
if (check_jni) {
@@ -2669,10 +2665,6 @@ JavaVMExt::JavaVMExt(Runtime* runtime, Runtime::ParsedOptions* options)
}
JavaVMExt::~JavaVMExt() {
- delete pins_lock;
- delete globals_lock;
- delete weak_globals_lock;
- delete libraries_lock;
delete libraries;
}
diff --git a/src/jni_internal.h b/src/jni_internal.h
index a0fe8fc..a723b32 100644
--- a/src/jni_internal.h
+++ b/src/jni_internal.h
@@ -8,6 +8,7 @@
#include "heap.h"
#include "indirect_reference_table.h"
#include "macros.h"
+#include "mutex.h"
#include "reference_table.h"
#include "runtime.h"
@@ -18,7 +19,6 @@ namespace art {
class ClassLoader;
class Libraries;
class Method;
-class Mutex;
class Thread;
void JniAbort(const char* jni_function_name);
@@ -64,18 +64,18 @@ struct JavaVMExt : public JavaVM {
bool work_around_app_jni_bugs;
// Used to hold references to pinned primitive arrays.
- Mutex* pins_lock;
+ Mutex pins_lock;
ReferenceTable pin_table;
// JNI global references.
- Mutex* globals_lock;
+ Mutex globals_lock;
IndirectReferenceTable globals;
// JNI weak global references.
- Mutex* weak_globals_lock;
+ Mutex weak_globals_lock;
IndirectReferenceTable weak_globals;
- Mutex* libraries_lock;
+ Mutex libraries_lock;
Libraries* libraries;
// Used by -Xcheck:jni.
diff --git a/src/logging.cc b/src/logging.cc
index 03788c3..5e9ae3a 100644
--- a/src/logging.cc
+++ b/src/logging.cc
@@ -22,8 +22,8 @@
namespace {
-art::Mutex* GetLoggingLock() {
- static art::Mutex* lock = art::Mutex::Create("LogMessage lock");
+art::Mutex& GetLoggingLock() {
+ static art::Mutex lock("LogMessage lock");
return lock;
}
diff --git a/src/logging.h b/src/logging.h
index 66190ac..43596b5 100644
--- a/src/logging.h
+++ b/src/logging.h
@@ -72,20 +72,8 @@
#define DCHECK_STREQ(s1, s2) CHECK_STREQ(s1, s2)
#define DCHECK_STRNE(s1, s2) CHECK_STRNE(s1, s2)
- // These require "utils.h" and only work with bionic (not glibc).
-#ifdef __BIONIC__
-#define DCHECK_LOCK_HELD(l) CHECK_EQ(art::GetOwner(l->GetImpl()), art::GetTid())
-#define DCHECK_LOCK_NOT_HELD(l) CHECK_NE(art::GetOwner(l->GetImpl()), art::GetTid())
-#else
-#define DCHECK_LOCK_HELD(l)
-#define DCHECK_LOCK_NOT_HELD(l)
-#endif
-
#else // NDEBUG
-#define DCHECK_LOCK_HELD(l)
-#define DCHECK_LOCK_NOT_HELD(l)
-
#define DCHECK(condition) \
while (false) \
CHECK(condition)
diff --git a/src/mutex.cc b/src/mutex.cc
new file mode 100644
index 0000000..4dba6b7
--- /dev/null
+++ b/src/mutex.cc
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#include "mutex.h"
+
+#include <errno.h>
+
+#include "logging.h"
+#include "utils.h"
+
+namespace art {
+
+Mutex::Mutex(const char* name) : name_(name) {
+#ifndef NDEBUG
+ pthread_mutexattr_t debug_attributes;
+ errno = pthread_mutexattr_init(&debug_attributes);
+ if (errno != 0) {
+ PLOG(FATAL) << "pthread_mutexattr_init failed";
+ }
+#if VERIFY_OBJECT_ENABLED
+ errno = pthread_mutexattr_settype(&debug_attributes, PTHREAD_MUTEX_RECURSIVE);
+#else
+ errno = pthread_mutexattr_settype(&debug_attributes, PTHREAD_MUTEX_ERRORCHECK);
+#endif
+ if (errno != 0) {
+ PLOG(FATAL) << "pthread_mutexattr_settype failed";
+ }
+ errno = pthread_mutex_init(&mutex_, &debug_attributes);
+ if (errno != 0) {
+ PLOG(FATAL) << "pthread_mutex_init failed";
+ }
+ errno = pthread_mutexattr_destroy(&debug_attributes);
+ if (errno != 0) {
+ PLOG(FATAL) << "pthread_mutexattr_destroy failed";
+ }
+#else
+ errno = pthread_mutex_init(&mutex_, NULL);
+ if (errno != 0) {
+ PLOG(FATAL) << "pthread_mutex_init failed";
+ }
+#endif
+}
+
+Mutex::~Mutex() {
+ errno = pthread_mutex_destroy(&mutex_);
+ if (errno != 0) {
+ PLOG(FATAL) << "pthread_mutex_destroy failed";
+ }
+}
+
+void Mutex::Lock() {
+ int result = pthread_mutex_lock(&mutex_);
+ if (result != 0) {
+ errno = result;
+ PLOG(FATAL) << "pthread_mutex_lock failed";
+ }
+}
+
+bool Mutex::TryLock() {
+ int result = pthread_mutex_trylock(&mutex_);
+ if (result == EBUSY) {
+ return false;
+ }
+ if (result != 0) {
+ errno = result;
+ PLOG(FATAL) << "pthread_mutex_trylock failed";
+ }
+ return true;
+}
+
+void Mutex::Unlock() {
+ int result = pthread_mutex_unlock(&mutex_);
+ if (result != 0) {
+ errno = result;
+ PLOG(FATAL) << "pthread_mutex_unlock failed";
+ }
+}
+
+pid_t Mutex::GetOwner() {
+#ifdef __BIONIC__
+ return static_cast<pid_t>((mutex_.value >> 16) & 0xffff);
+#else
+ UNIMPLEMENTED(FATAL);
+ return 0;
+#endif
+}
+
+pid_t Mutex::GetTid() {
+ return art::GetTid();
+}
+
+} // namespace
diff --git a/src/mutex.h b/src/mutex.h
new file mode 100644
index 0000000..cbfd5a0
--- /dev/null
+++ b/src/mutex.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#ifndef ART_SRC_MUTEX_H_
+#define ART_SRC_MUTEX_H_
+
+#include <pthread.h>
+#include <string>
+
+#include "logging.h"
+#include "macros.h"
+
+namespace art {
+
+class Mutex {
+ public:
+ explicit Mutex(const char* name);
+ ~Mutex();
+
+ void Lock();
+
+ bool TryLock();
+
+ void Unlock();
+
+ const char* GetName() {
+ return name_.c_str();
+ }
+
+ pthread_mutex_t* GetImpl() {
+ return &mutex_;
+ }
+
+ void AssertHeld() {
+#ifdef __BIONIC__
+ DCHECK_EQ(GetOwner(), GetTid());
+#endif
+ }
+
+ void AssertNotHeld() {
+#ifdef __BIONIC__
+ DCHECK_NE(GetOwner(), GetTid());
+#endif
+ }
+
+ private:
+ pid_t GetOwner();
+ pid_t GetTid();
+
+ std::string name_;
+
+ pthread_mutex_t mutex_;
+
+ DISALLOW_COPY_AND_ASSIGN(Mutex);
+};
+
+class MutexLock {
+ public:
+ explicit MutexLock(Mutex& mu) : mu_(mu) {
+ mu_.Lock();
+ }
+
+ ~MutexLock() {
+ mu_.Unlock();
+ }
+
+ private:
+ Mutex& mu_;
+ DISALLOW_COPY_AND_ASSIGN(MutexLock);
+};
+
+} // namespace art
+
+#endif // ART_SRC_MUTEX_H_
diff --git a/src/runtime.cc b/src/runtime.cc
index 9517bc2..454a38c 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -14,6 +14,7 @@
#include "jni_internal.h"
#include "signal_catcher.h"
#include "thread.h"
+#include "thread_list.h"
// TODO: this drags in cutil/log.h, which conflicts with our logging.h.
#include "JniConstants.h"
@@ -363,7 +364,7 @@ bool Runtime::Init(const Options& raw_options, bool ignore_unrecognized) {
abort_ = options->hook_abort_;
default_stack_size_ = options->stack_size_;
- thread_list_ = ThreadList::Create();
+ thread_list_ = new ThreadList;
intern_table_ = new InternTable;
@@ -407,18 +408,17 @@ void Runtime::InitLibraries() {
void Runtime::RegisterRuntimeNativeMethods(JNIEnv* env) {
#define REGISTER(FN) extern void FN(JNIEnv*); FN(env)
- //REGISTER(register_dalvik_bytecode_OpcodeInfo);
//REGISTER(register_dalvik_system_DexFile);
//REGISTER(register_dalvik_system_VMDebug);
//REGISTER(register_dalvik_system_VMRuntime);
- //REGISTER(register_dalvik_system_VMStack);
+ REGISTER(register_dalvik_system_VMStack);
//REGISTER(register_dalvik_system_Zygote);
//REGISTER(register_java_lang_Class);
REGISTER(register_java_lang_Object);
REGISTER(register_java_lang_Runtime);
REGISTER(register_java_lang_String);
REGISTER(register_java_lang_System);
- //REGISTER(register_java_lang_Thread);
+ REGISTER(register_java_lang_Thread);
REGISTER(register_java_lang_Throwable);
//REGISTER(register_java_lang_VMClassLoader);
//REGISTER(register_java_lang_reflect_AccessibleObject);
@@ -434,7 +434,7 @@ void Runtime::RegisterRuntimeNativeMethods(JNIEnv* env) {
#undef REGISTER
}
-void Runtime::DumpStatistics(std::ostream& os) {
+void Runtime::Dump(std::ostream& os) {
// TODO: dump other runtime statistics?
os << "Loaded classes: " << class_linker_->NumLoadedClasses() << "\n";
os << "Intern table size: " << GetInternTable()->Size() << "\n";
@@ -445,6 +445,8 @@ void Runtime::DumpStatistics(std::ostream& os) {
// gDvm.pBootLoaderAlloc->curOffset);
// LOGI("GC precise methods: %d", dvmPointerSetGetCount(gDvm.preciseMethods));
os << "\n";
+
+ thread_list_->Dump(os);
}
void Runtime::BlockSignals() {
diff --git a/src/runtime.h b/src/runtime.h
index 99caa29..bcb118c 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -92,7 +92,7 @@ class Runtime {
// Detaches the current native thread from the runtime.
void DetachCurrentThread();
- void DumpStatistics(std::ostream& os);
+ void Dump(std::ostream& os);
~Runtime();
diff --git a/src/signal_catcher.cc b/src/signal_catcher.cc
index 1552180..7061b36 100644
--- a/src/signal_catcher.cc
+++ b/src/signal_catcher.cc
@@ -29,8 +29,7 @@
namespace art {
-SignalCatcher::SignalCatcher() {
- lock_ = Mutex::Create("SignalCatcher lock");
+SignalCatcher::SignalCatcher() : lock_("SignalCatcher lock") {
SetHaltFlag(false);
// Create a raw pthread; its start routine will attach to the runtime.
@@ -72,9 +71,7 @@ void SignalCatcher::HandleSigQuit() {
os << "Cmd line: " << cmdline << "\n";
}
- Runtime* runtime = Runtime::Current();
- runtime->DumpStatistics(os);
- runtime->GetThreadList()->Dump(os);
+ Runtime::Current()->Dump(os);
std::string maps;
if (ReadFileToString("/proc/self/maps", &maps)) {
diff --git a/src/signal_catcher.h b/src/signal_catcher.h
index 8d91a94..dc05d06 100644
--- a/src/signal_catcher.h
+++ b/src/signal_catcher.h
@@ -17,11 +17,10 @@
#ifndef ART_SRC_SIGNAL_CATCHER_H_
#define ART_SRC_SIGNAL_CATCHER_H_
-#include <pthread.h>
+#include "mutex.h"
namespace art {
-class Mutex;
class Runtime;
class Thread;
@@ -44,7 +43,7 @@ class SignalCatcher {
void SetHaltFlag(bool new_value);
bool ShouldHalt();
- Mutex* lock_;
+ mutable Mutex lock_;
bool halt_;
pthread_t thread_;
};
diff --git a/src/thread.cc b/src/thread.cc
index 78cb1c6..4b477b8 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -17,6 +17,7 @@
#include "object.h"
#include "runtime.h"
#include "runtime_support.h"
+#include "thread_list.h"
#include "utils.h"
namespace art {
@@ -310,74 +311,6 @@ void Thread::InitFunctionPointers() {
pDebugMe = DebugMe;
}
-Mutex::~Mutex() {
- errno = pthread_mutex_destroy(&mutex_);
- if (errno != 0) {
- PLOG(FATAL) << "pthread_mutex_destroy failed";
- }
-}
-
-Mutex* Mutex::Create(const char* name) {
- Mutex* mu = new Mutex(name);
-#ifndef NDEBUG
- pthread_mutexattr_t debug_attributes;
- errno = pthread_mutexattr_init(&debug_attributes);
- if (errno != 0) {
- PLOG(FATAL) << "pthread_mutexattr_init failed";
- }
-#if VERIFY_OBJECT_ENABLED
- errno = pthread_mutexattr_settype(&debug_attributes, PTHREAD_MUTEX_RECURSIVE);
-#else
- errno = pthread_mutexattr_settype(&debug_attributes, PTHREAD_MUTEX_ERRORCHECK);
-#endif
- if (errno != 0) {
- PLOG(FATAL) << "pthread_mutexattr_settype failed";
- }
- errno = pthread_mutex_init(&mu->mutex_, &debug_attributes);
- if (errno != 0) {
- PLOG(FATAL) << "pthread_mutex_init failed";
- }
- errno = pthread_mutexattr_destroy(&debug_attributes);
- if (errno != 0) {
- PLOG(FATAL) << "pthread_mutexattr_destroy failed";
- }
-#else
- errno = pthread_mutex_init(&mu->mutex_, NULL);
- if (errno != 0) {
- PLOG(FATAL) << "pthread_mutex_init failed";
- }
-#endif
- return mu;
-}
-
-void Mutex::Lock() {
- int result = pthread_mutex_lock(&mutex_);
- if (result != 0) {
- errno = result;
- PLOG(FATAL) << "pthread_mutex_lock failed";
- }
-}
-
-bool Mutex::TryLock() {
- int result = pthread_mutex_trylock(&mutex_);
- if (result == EBUSY) {
- return false;
- }
- if (result != 0) {
- errno = result;
- PLOG(FATAL) << "pthread_mutex_trylock failed";
- }
- return true;
-}
-
-void Mutex::Unlock() {
- int result = pthread_mutex_unlock(&mutex_);
- if (result != 0) {
- errno = result;
- PLOG(FATAL) << "pthread_mutex_unlock failed";
- }
-}
-
void Frame::Next() {
byte* next_sp = reinterpret_cast<byte*>(sp_) +
GetMethod()->GetFrameSizeInBytes();
@@ -478,15 +411,14 @@ void Thread::CreatePeer(const char* name, bool as_daemon) {
jobject thread_group = NULL;
jobject thread_name = env->NewStringUTF(name);
- jint thread_priority = 123;
+ jint thread_priority = GetNativePriority();
jboolean thread_is_daemon = as_daemon;
jclass c = env->FindClass("java/lang/Thread");
jmethodID mid = env->GetMethodID(c, "<init>", "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V");
- jobject o = env->NewObject(c, mid, thread_group, thread_name, thread_priority, thread_is_daemon);
- LOG(INFO) << "Created new java.lang.Thread " << (void*) o << " decoded=" << (void*) DecodeJObject(o);
- peer_ = DecodeJObject(o);
+ jobject peer = env->NewObject(c, mid, thread_group, thread_name, thread_priority, thread_is_daemon);
+ peer_ = env->NewGlobalRef(peer);
}
void Thread::InitStackHwm() {
@@ -631,7 +563,6 @@ void Thread::DumpState(std::ostream& os) const {
int suspend_count = 0; // TODO
int debug_suspend_count = 0; // TODO
- void* peer_ = NULL; // TODO
os << " | group=\"" << group_name << "\""
<< " sCount=" << suspend_count
<< " dsCount=" << debug_suspend_count
@@ -706,6 +637,10 @@ void Thread::Shutdown() {
Thread::Thread()
: peer_(NULL),
+ wait_mutex_("Thread wait mutex"),
+ wait_monitor_(NULL),
+ interrupted_(false),
+ stack_end_(NULL),
top_of_managed_stack_(),
native_to_managed_record_(NULL),
top_sirt_(NULL),
@@ -714,11 +649,8 @@ Thread::Thread()
suspend_count_(0),
class_loader_override_(NULL) {
InitCpu();
- {
- ThreadListLock mu;
- thin_lock_id_ = Runtime::Current()->GetThreadList()->AllocThreadId();
- }
InitFunctionPointers();
+ thin_lock_id_ = Runtime::Current()->GetThreadList()->AllocThreadId();
}
void MonitorExitVisitor(const Object* object, void*) {
@@ -754,6 +686,10 @@ Thread::~Thread() {
//dvmUnlockObject(self, lock);
//lock = NULL;
+ // Delete our global reference to the java.lang.Thread.
+ jni_env_->DeleteGlobalRef(peer_);
+ peer_ = NULL;
+
delete jni_env_;
jni_env_ = NULL;
@@ -1057,102 +993,10 @@ std::ostream& operator<<(std::ostream& os, const Thread& thread) {
<< ",pthread_t=" << thread.GetImpl()
<< ",tid=" << thread.GetTid()
<< ",id=" << thread.GetThinLockId()
- << ",state=" << thread.GetState() << "]";
+ << ",state=" << thread.GetState()
+ << ",peer=" << thread.GetPeer()
+ << "]";
return os;
}
-ThreadList* ThreadList::Create() {
- return new ThreadList;
-}
-
-ThreadList::ThreadList() {
- lock_ = Mutex::Create("ThreadList::Lock");
-}
-
-ThreadList::~ThreadList() {
- if (Contains(Thread::Current())) {
- Runtime::Current()->DetachCurrentThread();
- }
-
- // All threads should have exited and unregistered when we
- // reach this point. This means that all daemon threads had been
- // shutdown cleanly.
- // TODO: dump ThreadList if non-empty.
- CHECK_EQ(list_.size(), 0U);
-
- delete lock_;
- lock_ = NULL;
-}
-
-bool ThreadList::Contains(Thread* thread) {
- return find(list_.begin(), list_.end(), thread) != list_.end();
-}
-
-void ThreadList::Dump(std::ostream& os) {
- MutexLock mu(lock_);
- os << "DALVIK THREADS (" << list_.size() << "):\n";
- typedef std::list<Thread*>::const_iterator It; // TODO: C++0x auto
- for (It it = list_.begin(), end = list_.end(); it != end; ++it) {
- (*it)->Dump(os);
- os << "\n";
- }
-}
-
-void ThreadList::Register(Thread* thread) {
- //LOG(INFO) << "ThreadList::Register() " << *thread;
- MutexLock mu(lock_);
- CHECK(!Contains(thread));
- list_.push_back(thread);
-}
-
-void ThreadList::Unregister() {
- Thread* self = Thread::Current();
-
- //LOG(INFO) << "ThreadList::Unregister() " << self;
- MutexLock mu(lock_);
-
- // Remove this thread from the list.
- CHECK(Contains(self));
- list_.remove(self);
-
- // Delete the Thread* and release the thin lock id.
- uint32_t thin_lock_id = self->thin_lock_id_;
- delete self;
- ReleaseThreadId(thin_lock_id);
-
- // Clear the TLS data, so that thread is recognizably detached.
- // (It may wish to reattach later.)
- errno = pthread_setspecific(Thread::pthread_key_self_, NULL);
- if (errno != 0) {
- PLOG(FATAL) << "pthread_setspecific failed";
- }
-}
-
-void ThreadList::VisitRoots(Heap::RootVisitor* visitor, void* arg) const {
- MutexLock mu(lock_);
- typedef std::list<Thread*>::const_iterator It; // TODO: C++0x auto
- for (It it = list_.begin(), end = list_.end(); it != end; ++it) {
- (*it)->VisitRoots(visitor, arg);
- }
-}
-
-uint32_t ThreadList::AllocThreadId() {
- DCHECK_LOCK_HELD(lock_);
- for (size_t i = 0; i < allocated_ids_.size(); ++i) {
- if (!allocated_ids_[i]) {
- allocated_ids_.set(i);
- return i + 1; // Zero is reserved to mean "invalid".
- }
- }
- LOG(FATAL) << "Out of internal thread ids";
- return 0;
-}
-
-void ThreadList::ReleaseThreadId(uint32_t id) {
- DCHECK_LOCK_HELD(lock_);
- --id; // Zero is reserved to mean "invalid".
- DCHECK(allocated_ids_[id]) << id;
- allocated_ids_.reset(id);
-}
-
-} // namespace
+} // namespace art
diff --git a/src/thread.h b/src/thread.h
index 4d27151..3f6228a 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -8,12 +8,14 @@
#include <bitset>
#include <iosfwd>
#include <list>
+#include <string>
#include "dex_file.h"
#include "globals.h"
#include "jni_internal.h"
#include "logging.h"
#include "macros.h"
+#include "mutex.h"
#include "mem_map.h"
#include "offsets.h"
@@ -24,6 +26,7 @@ class Class;
class ClassLinker;
class ClassLoader;
class Method;
+class Monitor;
class Object;
class Runtime;
class Thread;
@@ -36,43 +39,6 @@ template<class T> class ObjectArray;
template<class T> class PrimitiveArray;
typedef PrimitiveArray<int32_t> IntArray;
-class Mutex {
- public:
- ~Mutex();
-
- void Lock();
-
- bool TryLock();
-
- void Unlock();
-
- const char* GetName() { return name_; }
-
- static Mutex* Create(const char* name);
-
- pthread_mutex_t* GetImpl() { return &mutex_; }
-
- private:
- explicit Mutex(const char* name) : name_(name) {}
-
- const char* name_;
-
- pthread_mutex_t mutex_;
-
- DISALLOW_COPY_AND_ASSIGN(Mutex);
-};
-
-class MutexLock {
- public:
- explicit MutexLock(Mutex *mu) : mu_(mu) {
- mu_->Lock();
- }
- ~MutexLock() { mu_->Unlock(); }
- private:
- Mutex* const mu_;
- DISALLOW_COPY_AND_ASSIGN(MutexLock);
-};
-
// Stack allocated indirect reference table, allocated within the bridge frame
// between managed and native code.
class StackIndirectReferenceTable {
@@ -155,6 +121,12 @@ class Frame {
class Thread {
public:
+ /* thread priorities, from java.lang.Thread */
+ enum Priority {
+ kMinPriority = 1,
+ kNormPriority = 5,
+ kMaxPriority = 10,
+ };
enum State {
kUnknown = -1,
kNew,
@@ -250,6 +222,13 @@ class Thread {
return reinterpret_cast<Thread*>(thread);
}
+ static Thread* FromManagedThread(JNIEnv* env, jobject thread) {
+ // TODO: make these more generally available, and cached.
+ jclass java_lang_Thread = env->FindClass("java/lang/Thread");
+ jfieldID fid = env->GetFieldID(java_lang_Thread, "vmData", "I");
+ return reinterpret_cast<Thread*>(static_cast<uintptr_t>(env->GetIntField(thread, fid)));
+ }
+
void Dump(std::ostream& os) const;
State GetState() const {
@@ -262,6 +241,22 @@ class Thread {
return old_state;
}
+ /*
+ * Changes the priority of this thread to match that of the java.lang.Thread object.
+ *
+ * We map a priority value from 1-10 to Linux "nice" values, where lower
+ * numbers indicate higher priority.
+ */
+ void SetNativePriority(int newPriority);
+
+ /*
+ * Returns the thread priority for the current thread by querying the system.
+ * This is useful when attaching a thread through JNI.
+ *
+ * Returns a value from 1 to 10 (compatible with java.lang.Thread values).
+ */
+ static int GetNativePriority();
+
bool CanAccessDirectReferences() const {
// TODO: when we have a moving collector, we'll need: return state_ == kRunnable;
return true;
@@ -279,6 +274,10 @@ class Thread {
return pthread_;
}
+ jobject GetPeer() const {
+ return peer_;
+ }
+
// Returns the Method* for the current method.
// This is used by the JNI implementation for logging and diagnostic purposes.
const Method* GetCurrentMethod() const {
@@ -353,6 +352,20 @@ class Thread {
// Convert a jobject into a Object*
Object* DecodeJObject(jobject obj);
+ // Implements java.lang.Thread.interrupted.
+ bool Interrupted() {
+ MutexLock mu(wait_mutex_);
+ bool interrupted = interrupted_;
+ interrupted_ = false;
+ return interrupted;
+ }
+
+ // Implements java.lang.Thread.isInterrupted.
+ bool IsInterrupted() {
+ MutexLock mu(wait_mutex_);
+ return interrupted_;
+ }
+
void RegisterExceptionEntryPoint(void (*handler)(Method**)) {
exception_entry_point_ = handler;
}
@@ -480,7 +493,14 @@ class Thread {
bool is_daemon_;
// Our managed peer (an instance of java.lang.Thread).
- Object* peer_;
+ jobject peer_;
+
+ // Guards the 'interrupted_' and 'wait_monitor_' members.
+ mutable Mutex wait_mutex_;
+ // Pointer to the monitor lock we're currently waiting on (or NULL), guarded by wait_mutex_.
+ Monitor* wait_monitor_;
+ // Thread "interrupted" status; stays raised until queried or thrown, guarded by wait_mutex_.
+ bool interrupted_;
// FIXME: placeholder for the gc cardTable
uint32_t card_table_;
@@ -538,79 +558,6 @@ class Thread {
std::ostream& operator<<(std::ostream& os, const Thread& thread);
std::ostream& operator<<(std::ostream& os, const Thread::State& state);
-class ThreadList {
- public:
- static const uint32_t kMaxThreadId = 0xFFFF;
- static const uint32_t kInvalidId = 0;
- static const uint32_t kMainId = 1;
-
- static ThreadList* Create();
-
- ~ThreadList();
-
- void Dump(std::ostream& os);
-
- void Register(Thread* thread);
-
- void Unregister();
-
- bool Contains(Thread* thread);
-
- void VisitRoots(Heap::RootVisitor* visitor, void* arg) const;
-
- private:
- ThreadList();
-
- uint32_t AllocThreadId();
- void ReleaseThreadId(uint32_t id);
-
- void Lock() {
- lock_->Lock();
- }
-
- void Unlock() {
- lock_->Unlock();
- }
-
- Mutex* lock_;
-
- std::bitset<kMaxThreadId> allocated_ids_;
- std::list<Thread*> list_;
-
- friend class Thread;
- friend class ThreadListLock;
-
- DISALLOW_COPY_AND_ASSIGN(ThreadList);
-};
-
-class ThreadListLock {
- public:
- ThreadListLock(Thread* self = NULL) {
- if (self == NULL) {
- // Try to get it from TLS.
- self = Thread::Current();
- }
- Thread::State old_state;
- if (self != NULL) {
- old_state = self->SetState(Thread::kWaiting); // TODO: VMWAIT
- } else {
- // This happens during VM shutdown.
- old_state = Thread::kUnknown;
- }
- Runtime::Current()->GetThreadList()->Lock();
- if (self != NULL) {
- self->SetState(old_state);
- }
- }
-
- ~ThreadListLock() {
- Runtime::Current()->GetThreadList()->Unlock();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ThreadListLock);
-};
-
class ScopedThreadStateChange {
public:
ScopedThreadStateChange(Thread* thread, Thread::State new_state) : thread_(thread) {
diff --git a/src/thread_android.cc b/src/thread_android.cc
new file mode 100644
index 0000000..295a509
--- /dev/null
+++ b/src/thread_android.cc
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#include "thread.h"
+
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <limits.h>
+#include <errno.h>
+
+#include <cutils/sched_policy.h>
+#include <utils/threads.h>
+
+#include "macros.h"
+
+namespace art {
+
+/*
+ * Conversion map for "nice" values.
+ *
+ * We use Android thread priority constants to be consistent with the rest
+ * of the system. In some cases adjacent entries may overlap.
+ */
+static const int kNiceValues[10] = {
+ ANDROID_PRIORITY_LOWEST, /* 1 (MIN_PRIORITY) */
+ ANDROID_PRIORITY_BACKGROUND + 6,
+ ANDROID_PRIORITY_BACKGROUND + 3,
+ ANDROID_PRIORITY_BACKGROUND,
+ ANDROID_PRIORITY_NORMAL, /* 5 (NORM_PRIORITY) */
+ ANDROID_PRIORITY_NORMAL - 2,
+ ANDROID_PRIORITY_NORMAL - 4,
+ ANDROID_PRIORITY_URGENT_DISPLAY + 3,
+ ANDROID_PRIORITY_URGENT_DISPLAY + 2,
+ ANDROID_PRIORITY_URGENT_DISPLAY /* 10 (MAX_PRIORITY) */
+};
+
+void Thread::SetNativePriority(int newPriority) {
+ if (newPriority < 1 || newPriority > 10) {
+ LOG(WARNING) << "bad priority " << newPriority;
+ newPriority = 5;
+ }
+
+ int newNice = kNiceValues[newPriority-1];
+ pid_t tid = GetTid();
+
+ if (newNice >= ANDROID_PRIORITY_BACKGROUND) {
+ set_sched_policy(tid, SP_BACKGROUND);
+ } else if (getpriority(PRIO_PROCESS, tid) >= ANDROID_PRIORITY_BACKGROUND) {
+ set_sched_policy(tid, SP_FOREGROUND);
+ }
+
+ if (setpriority(PRIO_PROCESS, tid, newNice) != 0) {
+ PLOG(INFO) << *this << " setPriority(PRIO_PROCESS, " << tid << ", " << newNice << ") failed";
+ }
+}
+
+int Thread::GetNativePriority() {
+ errno = 0;
+ int native_priority = getpriority(PRIO_PROCESS, 0);
+ if (native_priority == -1 && errno != 0) {
+ PLOG(WARNING) << "getpriority failed";
+ return Thread::kNormPriority;
+ }
+
+ int managed_priority = Thread::kMinPriority;
+ for (size_t i = 0; i < arraysize(kNiceValues); i++) {
+ if (native_priority >= kNiceValues[i]) {
+ break;
+ }
+ managed_priority++;
+ }
+ if (managed_priority > Thread::kMaxPriority) {
+ managed_priority = Thread::kMaxPriority;
+ }
+ return managed_priority;
+}
+
+} // namespace art
diff --git a/src/thread_linux.cc b/src/thread_linux.cc
new file mode 100644
index 0000000..2bbbb25
--- /dev/null
+++ b/src/thread_linux.cc
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#include "thread.h"
+
+namespace art {
+
+void Thread::SetNativePriority(int) {
+ // Do nothing.
+}
+
+int Thread::GetNativePriority() {
+ return Thread::kNormPriority;
+}
+
+} // namespace art
diff --git a/src/thread_list.cc b/src/thread_list.cc
new file mode 100644
index 0000000..b0626c7
--- /dev/null
+++ b/src/thread_list.cc
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#include "thread_list.h"
+
+namespace art {
+
+ThreadList::ThreadList() : lock_("ThreadList lock") {
+}
+
+ThreadList::~ThreadList() {
+ if (Contains(Thread::Current())) {
+ Runtime::Current()->DetachCurrentThread();
+ }
+
+ // All threads should have exited and unregistered when we
+ // reach this point. This means that all daemon threads had been
+ // shutdown cleanly.
+ // TODO: dump ThreadList if non-empty.
+ CHECK_EQ(list_.size(), 0U);
+}
+
+bool ThreadList::Contains(Thread* thread) {
+ return find(list_.begin(), list_.end(), thread) != list_.end();
+}
+
+void ThreadList::Dump(std::ostream& os) {
+ MutexLock mu(lock_);
+ os << "DALVIK THREADS (" << list_.size() << "):\n";
+ typedef std::list<Thread*>::const_iterator It; // TODO: C++0x auto
+ for (It it = list_.begin(), end = list_.end(); it != end; ++it) {
+ (*it)->Dump(os);
+ os << "\n";
+ }
+}
+
+void ThreadList::Register(Thread* thread) {
+ //LOG(INFO) << "ThreadList::Register() " << *thread;
+ MutexLock mu(lock_);
+ CHECK(!Contains(thread));
+ list_.push_back(thread);
+}
+
+void ThreadList::Unregister() {
+ Thread* self = Thread::Current();
+
+ //LOG(INFO) << "ThreadList::Unregister() " << self;
+ MutexLock mu(lock_);
+
+ // Remove this thread from the list.
+ CHECK(Contains(self));
+ list_.remove(self);
+
+ // Delete the Thread* and release the thin lock id.
+ uint32_t thin_lock_id = self->thin_lock_id_;
+ delete self;
+ ReleaseThreadId(thin_lock_id);
+
+ // Clear the TLS data, so that thread is recognizably detached.
+ // (It may wish to reattach later.)
+ errno = pthread_setspecific(Thread::pthread_key_self_, NULL);
+ if (errno != 0) {
+ PLOG(FATAL) << "pthread_setspecific failed";
+ }
+}
+
+void ThreadList::VisitRoots(Heap::RootVisitor* visitor, void* arg) const {
+ MutexLock mu(lock_);
+ typedef std::list<Thread*>::const_iterator It; // TODO: C++0x auto
+ for (It it = list_.begin(), end = list_.end(); it != end; ++it) {
+ (*it)->VisitRoots(visitor, arg);
+ }
+}
+
+uint32_t ThreadList::AllocThreadId() {
+ MutexLock mu(lock_);
+ for (size_t i = 0; i < allocated_ids_.size(); ++i) {
+ if (!allocated_ids_[i]) {
+ allocated_ids_.set(i);
+ return i + 1; // Zero is reserved to mean "invalid".
+ }
+ }
+ LOG(FATAL) << "Out of internal thread ids";
+ return 0;
+}
+
+void ThreadList::ReleaseThreadId(uint32_t id) {
+ lock_.AssertHeld();
+ --id; // Zero is reserved to mean "invalid".
+ DCHECK(allocated_ids_[id]) << id;
+ allocated_ids_.reset(id);
+}
+
+} // namespace art
diff --git a/src/thread_list.h b/src/thread_list.h
new file mode 100644
index 0000000..12fdde4
--- /dev/null
+++ b/src/thread_list.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#ifndef ART_SRC_THREAD_LIST_H_
+#define ART_SRC_THREAD_LIST_H_
+
+#include "mutex.h"
+#include "thread.h"
+
+namespace art {
+
+class ThreadList {
+ public:
+ static const uint32_t kMaxThreadId = 0xFFFF;
+ static const uint32_t kInvalidId = 0;
+ static const uint32_t kMainId = 1;
+
+ ThreadList();
+ ~ThreadList();
+
+ void Dump(std::ostream& os);
+
+ void Register(Thread* thread);
+
+ void Unregister();
+
+ bool Contains(Thread* thread);
+
+ void VisitRoots(Heap::RootVisitor* visitor, void* arg) const;
+
+ private:
+ uint32_t AllocThreadId();
+ void ReleaseThreadId(uint32_t id);
+
+ mutable Mutex lock_;
+ std::bitset<kMaxThreadId> allocated_ids_;
+ std::list<Thread*> list_;
+
+ friend class Thread;
+ friend class ThreadListLock;
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadList);
+};
+
+class ThreadListLock {
+ public:
+ ThreadListLock(Thread* self = NULL) {
+ if (self == NULL) {
+ // Try to get it from TLS.
+ self = Thread::Current();
+ }
+ Thread::State old_state;
+ if (self != NULL) {
+ old_state = self->SetState(Thread::kWaiting); // TODO: VMWAIT
+ } else {
+ // This happens during VM shutdown.
+ old_state = Thread::kUnknown;
+ }
+ Runtime::Current()->GetThreadList()->lock_.Lock();
+ if (self != NULL) {
+ self->SetState(old_state);
+ }
+ }
+
+ ~ThreadListLock() {
+ Runtime::Current()->GetThreadList()->lock_.Unlock();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ThreadListLock);
+};
+
+} // namespace art
+
+#endif // ART_SRC_THREAD_LIST_H_
diff --git a/src/utils.cc b/src/utils.cc
index fed8a5e..d146166 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -252,15 +252,6 @@ void SetThreadName(const char *threadName) {
#endif
}
-pid_t GetOwner(pthread_mutex_t* mutex) {
-#ifdef __BIONIC__
- return static_cast<pid_t>(((mutex)->value >> 16) & 0xffff);
-#else
- UNIMPLEMENTED(FATAL);
- return 0;
-#endif
-}
-
} // namespace art
// Neither bionic nor glibc exposes gettid(2).
diff --git a/src/utils.h b/src/utils.h
index 135ea59..e6ed1d2 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -181,9 +181,6 @@ void Split(const std::string& s, char delim, std::vector<std::string>& result);
// Returns the calling thread's tid. (The C libraries don't expose this.)
pid_t GetTid();
-// Returns the tid of the thread that owns the given pthread mutex, or 0.
-pid_t GetOwner(pthread_mutex_t* mutex);
-
// Sets the name of the current thread. The name may be truncated to an
// implementation-defined limit.
void SetThreadName(const char* name);