A little bit more of the threads implementation.
The most important change here is understanding that Thread's id_ field
was unrelated to java.lang.Thread's id field.
Change-Id: I832b92145332e1ded63a7824033dae684eeacf28
diff --git a/src/thread.cc b/src/thread.cc
index 97cc8ea..b99e38a 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -6,6 +6,7 @@
#include <sys/mman.h>
#include <algorithm>
+#include <bitset>
#include <cerrno>
#include <iostream>
#include <list>
@@ -216,6 +217,8 @@
}
Thread* Thread::Create(const Runtime* runtime) {
+ UNIMPLEMENTED(FATAL) << "need to pass in a java.lang.Thread";
+
size_t stack_size = runtime->GetStackSize();
Thread* new_thread = new Thread;
@@ -247,18 +250,48 @@
PLOG(FATAL) << "pthread_attr_destroy failed";
}
+ // TODO: get the "daemon" field from the java.lang.Thread.
+ // new_thread->is_daemon_ = dvmGetFieldBoolean(threadObj, gDvm.offJavaLangThread_daemon);
+
return new_thread;
}
-Thread* Thread::Attach(const Runtime* runtime) {
+static const uint32_t kMaxThreadId = ((1 << 16) - 1);
+std::bitset<kMaxThreadId> gAllocatedThreadIds;
+
+uint32_t AllocThreadId() {
+ Runtime::Current()->GetThreadList()->Lock();
+ for (size_t i = 0; i < gAllocatedThreadIds.size(); ++i) {
+ if (!gAllocatedThreadIds[i]) {
+ gAllocatedThreadIds.set(i);
+ Runtime::Current()->GetThreadList()->Unlock();
+ return i + 1; // Zero is reserved to mean "invalid".
+ }
+ }
+ LOG(FATAL) << "Out of internal thread ids";
+ return 0;
+}
+
+void ReleaseThreadId(uint32_t id) {
+ Runtime::Current()->GetThreadList()->Lock();
+ CHECK(gAllocatedThreadIds[id]);
+ gAllocatedThreadIds.reset(id);
+ Runtime::Current()->GetThreadList()->Unlock();
+}
+
+Thread* Thread::Attach(const Runtime* runtime, const char* name, bool as_daemon) {
Thread* thread = new Thread;
thread->InitCpu();
- thread->handle_ = pthread_self();
+ thread->thin_lock_id_ = AllocThreadId();
thread->tid_ = ::art::GetTid();
+ thread->handle_ = pthread_self();
+ thread->is_daemon_ = as_daemon;
thread->state_ = kRunnable;
+ SetThreadName(name);
+
errno = pthread_setspecific(Thread::pthread_key_self_, thread);
if (errno != 0) {
PLOG(FATAL) << "pthread_setspecific failed";
@@ -283,18 +316,19 @@
*/
os << "TODO: pin Thread before dumping\n";
#if 0
- if (java_thread_ == NULL) {
+ // TODO: dalvikvm had this limitation, but we probably still want to do our best.
+ if (peer_ == NULL) {
LOGI("Can't dump thread %d: threadObj not set", threadId);
return;
}
- dvmAddTrackedAlloc(java_thread_, NULL);
+ dvmAddTrackedAlloc(peer_, NULL);
#endif
DumpState(os);
DumpStack(os);
#if 0
- dvmReleaseTrackedAlloc(java_thread_, NULL);
+ dvmReleaseTrackedAlloc(peer_, NULL);
#endif
}
@@ -326,16 +360,22 @@
void Thread::DumpState(std::ostream& os) const {
std::string thread_name("unknown");
int priority = -1;
- bool is_daemon = false;
+
#if 0 // TODO
nameStr = (StringObject*) dvmGetFieldObject(threadObj, gDvm.offJavaLangThread_name);
threadName = dvmCreateCstrFromString(nameStr);
priority = dvmGetFieldInt(threadObj, gDvm.offJavaLangThread_priority);
- is_daemon = dvmGetFieldBoolean(threadObj, gDvm.offJavaLangThread_daemon);
#else
- thread_name = "TODO";
+ {
+ // TODO: this may be truncated; we should use the java.lang.Thread 'name' field instead.
+ std::string stats;
+ if (ReadFileToString(StringPrintf("/proc/self/task/%d/stat", GetTid()).c_str(), &stats)) {
+ size_t start = stats.find('(') + 1;
+ size_t end = stats.find(')') - start;
+ thread_name = stats.substr(start, end);
+ }
+ }
priority = -1;
- is_daemon = false;
#endif
int policy;
@@ -362,20 +402,20 @@
#endif
os << '"' << thread_name << '"';
- if (is_daemon) {
+ if (is_daemon_) {
os << " daemon";
}
os << " prio=" << priority
- << " tid=" << GetId()
+ << " tid=" << GetThinLockId()
<< " " << state_ << "\n";
int suspend_count = 0; // TODO
int debug_suspend_count = 0; // TODO
- void* java_thread_ = NULL; // TODO
+ void* peer_ = NULL; // TODO
os << " | group=\"" << group_name << "\""
<< " sCount=" << suspend_count
<< " dsCount=" << debug_suspend_count
- << " obj=" << reinterpret_cast<void*>(java_thread_)
+ << " obj=" << reinterpret_cast<void*>(peer_)
<< " self=" << reinterpret_cast<const void*>(this) << "\n";
os << " | sysTid=" << GetTid()
<< " nice=" << getpriority(PRIO_PROCESS, GetTid())
@@ -447,6 +487,19 @@
}
}
+Thread::Thread()
+ : thin_lock_id_(0),
+ peer_(NULL),
+ top_of_managed_stack_(),
+ native_to_managed_record_(NULL),
+ top_sirt_(NULL),
+ jni_env_(NULL),
+ exception_(NULL),
+ suspend_count_(0),
+ class_loader_override_(NULL) {
+ InitFunctionPointers();
+}
+
Thread::~Thread() {
delete jni_env_;
}
@@ -747,7 +800,7 @@
os << "Thread[" << &thread
<< ",pthread_t=" << thread.GetImpl()
<< ",tid=" << thread.GetTid()
- << ",id=" << thread.GetId()
+ << ",id=" << thread.GetThinLockId()
<< ",state=" << thread.GetState() << "]";
return os;
}
@@ -785,15 +838,15 @@
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";
}
- os << "\n";
}
void ThreadList::Register(Thread* thread) {
//LOG(INFO) << "ThreadList::Register() " << *thread;
MutexLock mu(lock_);
CHECK(!Contains(thread));
- list_.push_front(thread);
+ list_.push_back(thread);
}
void ThreadList::Unregister(Thread* thread) {