blob: 8d11541a6268a80f9c9dc7da7ef55ba77718a9ba [file] [log] [blame]
Carl Shapirob5573532011-07-12 18:22:59 -07001// Copyright 2011 Google Inc. All Rights Reserved.
2
Brian Carlstrom578bbdc2011-07-21 14:07:47 -07003#include "thread.h"
Carl Shapirob5573532011-07-12 18:22:59 -07004
Ian Rogersb033c752011-07-20 12:22:35 -07005#include <pthread.h>
6#include <sys/mman.h>
Carl Shapirob5573532011-07-12 18:22:59 -07007#include <algorithm>
Elliott Hugheseb4f6142011-07-15 17:43:51 -07008#include <cerrno>
Carl Shapirob5573532011-07-12 18:22:59 -07009#include <list>
Carl Shapirob5573532011-07-12 18:22:59 -070010
Elliott Hughesa5b897e2011-08-16 11:33:06 -070011#include "class_linker.h"
Elliott Hughesc5f7c912011-08-18 14:00:42 -070012#include "jni_internal.h"
Elliott Hughesa5b897e2011-08-16 11:33:06 -070013#include "object.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070014#include "runtime.h"
15#include "utils.h"
Carl Shapirob5573532011-07-12 18:22:59 -070016
17namespace art {
18
19pthread_key_t Thread::pthread_key_self_;
20
21Mutex* Mutex::Create(const char* name) {
22 Mutex* mu = new Mutex(name);
23 int result = pthread_mutex_init(&mu->lock_impl_, NULL);
Ian Rogersb033c752011-07-20 12:22:35 -070024 CHECK_EQ(0, result);
Carl Shapirob5573532011-07-12 18:22:59 -070025 return mu;
26}
27
28void Mutex::Lock() {
29 int result = pthread_mutex_lock(&lock_impl_);
30 CHECK_EQ(result, 0);
31 SetOwner(Thread::Current());
32}
33
34bool Mutex::TryLock() {
35 int result = pthread_mutex_lock(&lock_impl_);
36 if (result == EBUSY) {
37 return false;
38 } else {
39 CHECK_EQ(result, 0);
40 SetOwner(Thread::Current());
41 return true;
42 }
43}
44
45void Mutex::Unlock() {
46 CHECK(GetOwner() == Thread::Current());
47 int result = pthread_mutex_unlock(&lock_impl_);
48 CHECK_EQ(result, 0);
Elliott Hughesf4c21c92011-08-19 17:31:31 -070049 SetOwner(NULL);
Carl Shapirob5573532011-07-12 18:22:59 -070050}
51
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -070052void Frame::Next() {
53 byte* next_sp = reinterpret_cast<byte*>(sp_) +
54 GetMethod()->GetFrameSize();
55 sp_ = reinterpret_cast<const Method**>(next_sp);
56}
57
58void* Frame::GetPC() const {
59 byte* pc_addr = reinterpret_cast<byte*>(sp_) +
Ian Rogers762400c2011-08-23 12:14:16 -070060 GetMethod()->GetReturnPcOffset();
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -070061 return reinterpret_cast<void*>(pc_addr);
62}
63
64const Method* Frame::NextMethod() const {
65 byte* next_sp = reinterpret_cast<byte*>(sp_) +
66 GetMethod()->GetFrameSize();
67 return reinterpret_cast<const Method*>(next_sp);
68}
69
Carl Shapiro61e019d2011-07-14 16:53:09 -070070void* ThreadStart(void *arg) {
Elliott Hughes53b61312011-08-12 18:28:20 -070071 UNIMPLEMENTED(FATAL);
Carl Shapirob5573532011-07-12 18:22:59 -070072 return NULL;
73}
74
Brian Carlstromb765be02011-08-17 23:54:10 -070075Thread* Thread::Create(const Runtime* runtime) {
76 size_t stack_size = runtime->GetStackSize();
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070077 scoped_ptr<MemMap> stack(MemMap::Map(stack_size, PROT_READ | PROT_WRITE));
Brian Carlstromb765be02011-08-17 23:54:10 -070078 if (stack == NULL) {
79 LOG(FATAL) << "failed to allocate thread stack";
80 // notreached
81 return NULL;
Carl Shapiro61e019d2011-07-14 16:53:09 -070082 }
83
84 Thread* new_thread = new Thread;
Ian Rogers176f59c2011-07-20 13:14:11 -070085 new_thread->InitCpu();
Brian Carlstromb765be02011-08-17 23:54:10 -070086 new_thread->stack_.reset(stack.release());
87 // Since stacks are assumed to grown downward the base is the limit and the limit is the base.
88 new_thread->stack_limit_ = stack->GetAddress();
89 new_thread->stack_base_ = stack->GetLimit();
Carl Shapiro61e019d2011-07-14 16:53:09 -070090
91 pthread_attr_t attr;
92 int result = pthread_attr_init(&attr);
93 CHECK_EQ(result, 0);
94
95 result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
96 CHECK_EQ(result, 0);
97
98 pthread_t handle;
99 result = pthread_create(&handle, &attr, ThreadStart, new_thread);
100 CHECK_EQ(result, 0);
101
102 result = pthread_attr_destroy(&attr);
103 CHECK_EQ(result, 0);
104
105 return new_thread;
106}
107
Elliott Hughes515a5bc2011-08-17 11:08:34 -0700108Thread* Thread::Attach(const Runtime* runtime) {
Carl Shapiro61e019d2011-07-14 16:53:09 -0700109 Thread* thread = new Thread;
Ian Rogers176f59c2011-07-20 13:14:11 -0700110 thread->InitCpu();
Carl Shapiro61e019d2011-07-14 16:53:09 -0700111 thread->stack_limit_ = reinterpret_cast<byte*>(-1); // TODO: getrlimit
112 uintptr_t addr = reinterpret_cast<uintptr_t>(&thread); // TODO: ask pthreads
Brian Carlstromb0460ea2011-07-29 10:08:05 -0700113 uintptr_t stack_base = RoundUp(addr, kPageSize);
Carl Shapiro61e019d2011-07-14 16:53:09 -0700114 thread->stack_base_ = reinterpret_cast<byte*>(stack_base);
115 // TODO: set the stack size
116
117 thread->handle_ = pthread_self();
118
119 thread->state_ = kRunnable;
120
Elliott Hughesa5780da2011-07-17 11:39:39 -0700121 errno = pthread_setspecific(Thread::pthread_key_self_, thread);
122 if (errno != 0) {
123 PLOG(FATAL) << "pthread_setspecific failed";
124 }
125
Elliott Hughes0af55432011-08-17 18:37:28 -0700126 JavaVMExt* vm = runtime->GetJavaVM();
Elliott Hughes515a5bc2011-08-17 11:08:34 -0700127 CHECK(vm != NULL);
128 bool check_jni = vm->check_jni;
129 thread->jni_env_ = reinterpret_cast<JNIEnv*>(new JNIEnvExt(thread, check_jni));
Elliott Hughes330304d2011-08-12 14:28:05 -0700130
Carl Shapiro61e019d2011-07-14 16:53:09 -0700131 return thread;
132}
133
Carl Shapirob5573532011-07-12 18:22:59 -0700134static void ThreadExitCheck(void* arg) {
135 LG << "Thread exit check";
136}
137
138bool Thread::Init() {
139 // Allocate a TLS slot.
140 if (pthread_key_create(&Thread::pthread_key_self_, ThreadExitCheck) != 0) {
Elliott Hugheseb4f6142011-07-15 17:43:51 -0700141 PLOG(WARNING) << "pthread_key_create failed";
Carl Shapirob5573532011-07-12 18:22:59 -0700142 return false;
143 }
144
145 // Double-check the TLS slot allocation.
146 if (pthread_getspecific(pthread_key_self_) != NULL) {
Elliott Hugheseb4f6142011-07-15 17:43:51 -0700147 LOG(WARNING) << "newly-created pthread TLS slot is not NULL";
Carl Shapirob5573532011-07-12 18:22:59 -0700148 return false;
149 }
150
151 // TODO: initialize other locks and condition variables
152
153 return true;
154}
155
Ian Rogersa8cd9f42011-08-19 16:43:41 -0700156size_t Thread::NumShbHandles() {
157 size_t count = 0;
158 for (StackHandleBlock* cur = top_shb_; cur; cur = cur->Link()) {
159 count += cur->NumberOfReferences();
160 }
161 return count;
162}
163
164bool Thread::ShbContains(jobject obj) {
Brian Carlstrom4873d462011-08-21 15:23:39 -0700165 Object** shb_entry = reinterpret_cast<Object**>(obj);
Ian Rogersa8cd9f42011-08-19 16:43:41 -0700166 for (StackHandleBlock* cur = top_shb_; cur; cur = cur->Link()) {
167 size_t num_refs = cur->NumberOfReferences();
168 DCHECK_GT(num_refs, 0u); // A SHB should always have a jobject/jclass
169 if ((&cur->Handles()[0] >= shb_entry) &&
170 (shb_entry <= (&cur->Handles()[num_refs-1]))) {
171 return true;
172 }
173 }
174 return false;
175}
176
Elliott Hughese5b0dc82011-08-23 09:59:02 -0700177void Thread::ThrowNewException(const char* exception_class_descriptor, const char* fmt, ...) {
Elliott Hughes37f7a402011-08-22 18:56:01 -0700178 std::string msg;
Elliott Hughesa5b897e2011-08-16 11:33:06 -0700179 va_list args;
180 va_start(args, fmt);
Elliott Hughes37f7a402011-08-22 18:56:01 -0700181 StringAppendV(&msg, fmt, args);
Elliott Hughesa5b897e2011-08-16 11:33:06 -0700182 va_end(args);
Elliott Hughes37f7a402011-08-22 18:56:01 -0700183
Elliott Hughese5b0dc82011-08-23 09:59:02 -0700184 // Convert "Ljava/lang/Exception;" into JNI-style "java/lang/Exception".
185 CHECK(exception_class_descriptor[0] == 'L');
186 std::string descriptor(exception_class_descriptor + 1);
187 CHECK(descriptor[descriptor.length() - 1] == ';');
188 descriptor.erase(descriptor.length() - 1);
189
190 JNIEnv* env = GetJniEnv();
191 jclass exception_class = env->FindClass(descriptor.c_str());
192 CHECK(exception_class != NULL) << "descriptor=\"" << descriptor << "\"";
193 int rc = env->ThrowNew(exception_class, msg.c_str());
194 CHECK_EQ(rc, JNI_OK);
Elliott Hughesa5b897e2011-08-16 11:33:06 -0700195}
196
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -0700197Frame Thread::FindExceptionHandler(void* throw_pc, void** handler_pc) {
198 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
199 DCHECK(class_linker != NULL);
200
201 Frame cur_frame = GetTopOfStack();
202 for (int unwind_depth = 0; ; unwind_depth++) {
203 const Method* cur_method = cur_frame.GetMethod();
204 DexCache* dex_cache = cur_method->GetDeclaringClass()->GetDexCache();
205 const DexFile& dex_file = class_linker->FindDexFile(dex_cache);
206
207 void* handler_addr = FindExceptionHandlerInMethod(cur_method,
208 throw_pc,
209 dex_file,
210 class_linker);
211 if (handler_addr) {
212 *handler_pc = handler_addr;
213 return cur_frame;
214 } else {
215 // Check if we are at the last frame
216 if (cur_frame.HasNext()) {
217 cur_frame.Next();
218 } else {
219 // Either at the top of stack or next frame is native.
220 break;
221 }
222 }
223 }
224 *handler_pc = NULL;
225 return Frame();
226}
227
228void* Thread::FindExceptionHandlerInMethod(const Method* method,
229 void* throw_pc,
230 const DexFile& dex_file,
231 ClassLinker* class_linker) {
Elliott Hughese5b0dc82011-08-23 09:59:02 -0700232 Throwable* exception_obj = exception_;
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -0700233 exception_ = NULL;
234
235 intptr_t dex_pc = -1;
236 const DexFile::CodeItem* code_item = dex_file.GetCodeItem(method->code_off_);
237 DexFile::CatchHandlerIterator iter;
238 for (iter = dex_file.dexFindCatchHandler(*code_item,
239 method->ToDexPC(reinterpret_cast<intptr_t>(throw_pc)));
240 !iter.HasNext();
241 iter.Next()) {
242 Class* klass = class_linker->FindSystemClass(dex_file.dexStringByTypeIdx(iter.Get().type_idx_));
243 DCHECK(klass != NULL);
244 if (exception_obj->InstanceOf(klass)) {
245 dex_pc = iter.Get().address_;
246 break;
247 }
248 }
249
250 exception_ = exception_obj;
251 if (iter.HasNext()) {
252 return NULL;
253 } else {
254 return reinterpret_cast<void*>( method->ToNativePC(dex_pc) );
255 }
256}
257
Ian Rogersb033c752011-07-20 12:22:35 -0700258static const char* kStateNames[] = {
259 "New",
260 "Runnable",
261 "Blocked",
262 "Waiting",
263 "TimedWaiting",
264 "Native",
265 "Terminated",
266};
267std::ostream& operator<<(std::ostream& os, const Thread::State& state) {
268 if (state >= Thread::kNew && state <= Thread::kTerminated) {
269 os << kStateNames[state-Thread::kNew];
270 } else {
271 os << "State[" << static_cast<int>(state) << "]";
272 }
273 return os;
274}
275
Elliott Hughes330304d2011-08-12 14:28:05 -0700276std::ostream& operator<<(std::ostream& os, const Thread& thread) {
277 os << "Thread[" << &thread
278 << ",id=" << thread.GetId()
279 << ",tid=" << thread.GetNativeId()
280 << ",state=" << thread.GetState() << "]";
281 return os;
282}
283
Carl Shapiro61e019d2011-07-14 16:53:09 -0700284ThreadList* ThreadList::Create() {
285 return new ThreadList;
286}
287
Carl Shapirob5573532011-07-12 18:22:59 -0700288ThreadList::ThreadList() {
289 lock_ = Mutex::Create("ThreadList::Lock");
290}
291
292ThreadList::~ThreadList() {
293 // Make sure that all threads have exited and unregistered when we
294 // reach this point. This means that all daemon threads had been
295 // shutdown cleanly.
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700296 CHECK_LE(list_.size(), 1U);
Carl Shapiro7a909592011-07-24 19:21:59 -0700297 // TODO: wait for all other threads to unregister
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700298 CHECK(list_.size() == 0 || list_.front() == Thread::Current());
Carl Shapiro7a909592011-07-24 19:21:59 -0700299 // TODO: detach the current thread
Carl Shapirob5573532011-07-12 18:22:59 -0700300 delete lock_;
301 lock_ = NULL;
302}
303
304void ThreadList::Register(Thread* thread) {
305 MutexLock mu(lock_);
306 CHECK(find(list_.begin(), list_.end(), thread) == list_.end());
307 list_.push_front(thread);
308}
309
310void ThreadList::Unregister(Thread* thread) {
311 MutexLock mu(lock_);
312 CHECK(find(list_.begin(), list_.end(), thread) != list_.end());
313 list_.remove(thread);
314}
315
Carl Shapirob5573532011-07-12 18:22:59 -0700316} // namespace