Add more functionality to the thread and mutex implementation.
Change-Id: I33b2e53acb4c4c6653f13f1bbdd77cc7ce27e581
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 4798d63..30a63ca 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -49,7 +49,8 @@
src/object.cc \
src/raw_dex_file.cc \
src/runtime.cc \
- src/stringpiece.cc
+ src/stringpiece.cc \
+ src/thread.cc
ifeq ($(LIBART_TARGET_ARCH),arm)
LIBART_LOCAL_SRC_FILES += \
diff --git a/src/class_linker.cc b/src/class_linker.cc
index e1e9bef..cf72a11 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -41,7 +41,7 @@
Class* ClassLinker::FindClass(const char* descriptor,
Object* class_loader,
DexFile* dex_file) {
- Thread* self = Thread::Self();
+ Thread* self = Thread::Current();
CHECK(!self->IsExceptionPending());
// Find the class in the loaded classes table.
Class* klass = LookupClass(descriptor, class_loader);
@@ -74,7 +74,7 @@
}
{
ObjectLock lock(klass);
- klass->clinit_thread_id_ = self->GetThreadId();
+ klass->clinit_thread_id_ = self->GetId();
// Add the newly loaded class to the loaded classes table.
bool success = InsertClass(klass);
if (!success) {
@@ -98,7 +98,7 @@
if (!klass->IsLinked() && !klass->IsErroneous()) {
ObjectLock lock(klass);
// Check for circular dependencies between classes.
- if (!klass->IsLinked() && klass->clinit_thread_id_ == self->GetThreadId()) {
+ if (!klass->IsLinked() && klass->clinit_thread_id_ == self->GetId()) {
LG << "Recursive link"; // TODO: ClassCircularityError
return NULL;
}
@@ -198,7 +198,7 @@
CHECK(klass->GetStatus() == Class::kStatusResolved ||
klass->GetStatus() == Class::kStatusError);
- Thread* self = Thread::Self();
+ Thread* self = Thread::Current();
{
ObjectLock lock(klass);
@@ -230,7 +230,7 @@
while (klass->status_ == Class::kStatusInitializing) {
// we caught somebody else in the act; was it us?
- if (klass->clinit_thread_id_ == self->GetThreadId()) {
+ if (klass->clinit_thread_id_ == self->GetId()) {
LG << "recursive <clinit>";
return true;
}
@@ -280,7 +280,7 @@
assert(klass->status < CLASS_INITIALIZING);
- klass->clinit_thread_id_ = self->GetThreadId();
+ klass->clinit_thread_id_ = self->GetId();
klass->status_ = Class::kStatusInitializing;
}
@@ -390,7 +390,7 @@
// TODO: found2 == NULL
// TODO: lookup found1 in initiating loader list
if (found1 == NULL || found2 == NULL) {
- Thread::Self()->ClearException();
+ Thread::Current()->ClearException();
if (found1 == found2) {
return true;
} else {
@@ -996,7 +996,7 @@
}
dex_file->SetResolvedClass(resolved, class_idx);
} else {
- CHECK(Thread::Self()->IsExceptionPending());
+ CHECK(Thread::Current()->IsExceptionPending());
}
return resolved;
}
diff --git a/src/runtime.h b/src/runtime.h
index 2afd9f0..495ab1c 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -3,6 +3,8 @@
#ifndef ART_SRC_RUNTIME_H_
#define ART_SRC_RUNTIME_H_
+#include "src/thread.h"
+
namespace art {
class Runtime {
@@ -11,10 +13,15 @@
static void Shutdown();
static void Compile(const char* filename);
+
+ void SetThreadList(ThreadList* thread_list) {
+ thread_list_ = thread_list;
+ }
+
+ private:
+ ThreadList* thread_list_;
};
} // namespace art
-namespace r = art;
-
#endif // ART_SRC_RUNTIME_H_
diff --git a/src/thread.cc b/src/thread.cc
new file mode 100644
index 0000000..abd45db
--- /dev/null
+++ b/src/thread.cc
@@ -0,0 +1,104 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#include "src/thread.h"
+
+#include <algorithm>
+#include <list>
+#include <errno.h>
+#include <pthread.h>
+
+#include "src/runtime.h"
+
+namespace art {
+
+pthread_key_t Thread::pthread_key_self_;
+
+Mutex* Mutex::Create(const char* name) {
+ Mutex* mu = new Mutex(name);
+ int result = pthread_mutex_init(&mu->lock_impl_, NULL);
+ CHECK(result == 0);
+ return mu;
+}
+
+void Mutex::Lock() {
+ int result = pthread_mutex_lock(&lock_impl_);
+ CHECK_EQ(result, 0);
+ SetOwner(Thread::Current());
+}
+
+bool Mutex::TryLock() {
+ int result = pthread_mutex_lock(&lock_impl_);
+ if (result == EBUSY) {
+ return false;
+ } else {
+ CHECK_EQ(result, 0);
+ SetOwner(Thread::Current());
+ return true;
+ }
+}
+
+void Mutex::Unlock() {
+ CHECK(GetOwner() == Thread::Current());
+ int result = pthread_mutex_unlock(&lock_impl_);
+ CHECK_EQ(result, 0);
+ SetOwner(Thread::Current());
+}
+
+Thread* Thread::Create(const char* name) {
+ LOG(FATAL) << "Unimplemented";
+ return NULL;
+}
+
+static void ThreadExitCheck(void* arg) {
+ LG << "Thread exit check";
+}
+
+bool Thread::Init() {
+ // Allocate a TLS slot.
+ if (pthread_key_create(&Thread::pthread_key_self_, ThreadExitCheck) != 0) {
+ LOG(WARN) << "pthread_key_create failed";
+ return false;
+ }
+
+ // Double-check the TLS slot allocation.
+ if (pthread_getspecific(pthread_key_self_) != NULL) {
+ LOG(WARN) << "newly-created pthread TLS slot is not NULL";
+ return false;
+ }
+
+ // TODO: initialize other locks and condition variables
+
+ return true;
+}
+
+ThreadList::ThreadList() {
+ lock_ = Mutex::Create("ThreadList::Lock");
+}
+
+ThreadList::~ThreadList() {
+ // Make sure that all threads have exited and unregistered when we
+ // reach this point. This means that all daemon threads had been
+ // shutdown cleanly.
+ CHECK_EQ(list_.size(), 0);
+ delete lock_;
+ lock_ = NULL;
+}
+
+void ThreadList::Register(Thread* thread) {
+ MutexLock mu(lock_);
+ CHECK(find(list_.begin(), list_.end(), thread) == list_.end());
+ list_.push_front(thread);
+}
+
+void ThreadList::Unregister(Thread* thread) {
+ MutexLock mu(lock_);
+ CHECK(find(list_.begin(), list_.end(), thread) != list_.end());
+ list_.remove(thread);
+}
+
+void ThreadList::Init(Runtime* runtime) {
+ ThreadList* thread_list = new ThreadList();
+ runtime->SetThreadList(thread_list);
+}
+
+} // namespace
diff --git a/src/thread.h b/src/thread.h
index b1bfb33..6cc2135 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -4,6 +4,9 @@
#ifndef ART_SRC_THREAD_H_
#define ART_SRC_THREAD_H_
+#include <list>
+#include <pthread.h>
+
#include "src/globals.h"
#include "src/logging.h"
#include "src/macros.h"
@@ -11,22 +14,26 @@
namespace art {
class Object;
+class Runtime;
class Thread;
+class ThreadList;
class Mutex {
public:
virtual ~Mutex() {}
- void Lock() {}
+ void Lock();
- bool TryLock() { return true; }
+ bool TryLock();
- void Unlock() {}
+ void Unlock();
const char* GetName() { return name_; }
Thread* GetOwner() { return owner_; }
+ static Mutex* Create(const char* name);
+
public: // TODO: protected
explicit Mutex(const char* name) : name_(name), owner_(NULL) {}
@@ -37,6 +44,8 @@
Thread* owner_;
+ pthread_mutex_t lock_impl_;
+
DISALLOW_COPY_AND_ASSIGN(Mutex);
};
@@ -53,13 +62,29 @@
class Thread {
public:
- static Thread* Self() {
+ enum State {
+ kUnknown = -1,
+ kNew,
+ kRunnable,
+ kBlocked,
+ kWaiting,
+ kTimedWaiting,
+ kTerminated,
+ };
+
+ static Thread* Create(const char* name);
+
+ static Thread* Current() {
static Thread self;
return &self; // TODO
}
- uint32_t GetThreadId() {
- return thread_id_;
+ uint32_t GetId() const {
+ return id_;
+ }
+
+ pid_t GetNativeId() const {
+ return native_id_;
}
bool IsExceptionPending() const {
@@ -80,17 +105,118 @@
exception_ = NULL;
}
+ void SetName(const char* name);
+
+ void Suspend();
+
+ bool IsSuspended();
+
+ void Resume();
+
+ static bool Init();
+
+ Thread* next_;
+
+ Thread* prev_;
+
+ State GetState() {
+ return state_;
+ }
+
+ void SetState(State new_state) {
+ state_ = new_state;
+ }
+
private:
- Thread() : thread_id_(1234), exception_(NULL) {}
+ Thread() : id_(1234), exception_(NULL) {}
~Thread() {}
- uint32_t thread_id_;
+ State state_;
+
+ uint32_t id_;
+
+ pid_t native_id_;
+
+ pthread_t native_handle_;
Object* exception_;
+ static pthread_key_t pthread_key_self_;
+
DISALLOW_COPY_AND_ASSIGN(Thread);
};
+class ThreadList {
+ public:
+ static const int kMaxThreadId = 0xFFFF;
+ static const int kMainThreadId = 1;
+
+ void Init(Runtime* runtime);
+
+ void Register(Thread* thread);
+
+ void Unregister(Thread* thread);
+
+ void SuspendAll();
+
+ void ResumeAll();
+
+ ~ThreadList();
+
+ void Lock() {
+ lock_->Lock();
+ }
+
+ void Unlock() {
+ lock_->Unlock();
+ };
+
+ private:
+ ThreadList();
+
+ std::list<Thread*> list_;
+
+ Mutex* lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadList);
+};
+
+class ThreadListLock {
+ public:
+ ThreadListLock(ThreadList* thread_list, Thread* current_thread)
+ : thread_list_(thread_list) {
+ if (current_thread == NULL) { // try to get it from TLS
+ current_thread = Thread::Current();
+ }
+ Thread::State old_state;
+ if (current_thread != NULL) {
+ old_state = current_thread->GetState();
+ current_thread->SetState(Thread::kWaiting); // TODO: VMWAIT
+ } else {
+ // happens during VM shutdown
+ old_state = Thread::kUnknown; // TODO: something else
+ }
+ thread_list_->Lock();
+ if (current_thread != NULL) {
+ current_thread->SetState(old_state);
+ }
+ }
+
+ ~ThreadListLock() {
+ thread_list_->Unlock();
+ }
+
+ // Allocates
+ int AllocThreadId();
+
+ void FreeThreadId(int thread_id);
+
+ private:
+ ThreadList* thread_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadListLock);
+};
+
} // namespace art
#endif // ART_SRC_THREAD_H_