blob: 409db2aa963d0ffa9671dda937a795df3923572a [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
buzbee3ea4ec52011-08-22 17:37:19 -070021void Thread::InitFunctionPointers() {
22 pArtAllocArrayByClass = Array::Alloc;
23 pMemcpy = memcpy;
24#if 0
25//void* (Thread::*pMemcpy)(void*, const void*, size_t) /* = memcpy*/ ;
26float (Thread::*pI2f)(int);
27int (Thread::*pF2iz)(float);
28float (Thread::*pD2f)(double);
29double (Thread::*pF2d)(float);
30double (Thread::*pI2d)(int);
31int (Thread::*pD2iz)(double);
32float (Thread::*pL2f)(long);
33double (Thread::*pL2d)(long);
34long long (Thread::*pArtF2l)(float);
35long long (Thread::*pArtD2l)(double);
36float (Thread::*pFadd)(float, float);
37float (Thread::*pFsub)(float, float);
38float (Thread::*pFdiv)(float, float);
39float (Thread::*pFmul)(float, float);
40float (Thread::*pFmodf)(float, float);
41double (Thread::*pDadd)(double, double);
42double (Thread::*pDsub)(double, double);
43double (Thread::*pDdiv)(double, double);
44double (Thread::*pDmul)(double, double);
45double (Thread::*pFmod)(double, double);
46int (Thread::*pIdivmod)(int, int);
47int (Thread::*pIdiv)(int, int);
48long long (Thread::*pLdivmod)(long long, long long);
49bool (Thread::*pArtUnlockObject)(struct Thread*, struct Object*);
50bool (Thread::*pArtCanPutArrayElementNoThrow)(const struct ClassObject*,
51 const struct ClassObject*);
52int (Thread::*pArtInstanceofNonTrivialNoThrow)
53 (const struct ClassObject*, const struct ClassObject*);
54int (Thread::*pArtInstanceofNonTrivial) (const struct ClassObject*,
55 const struct ClassObject*);
56struct Method* (Thread::*pArtFindInterfaceMethodInCache)(ClassObject*, uint32_t,
57 const struct Method*, struct DvmDex*);
58bool (Thread::*pArtUnlockObjectNoThrow)(struct Thread*, struct Object*);
59void (Thread::*pArtLockObjectNoThrow)(struct Thread*, struct Object*);
60struct Object* (Thread::*pArtAllocObjectNoThrow)(struct ClassObject*, int);
61void (Thread::*pArtThrowException)(struct Thread*, struct Object*);
62bool (Thread::*pArtHandleFillArrayDataNoThrow)(struct ArrayObject*, const uint16_t*);
63#endif
64}
65
Carl Shapirob5573532011-07-12 18:22:59 -070066Mutex* Mutex::Create(const char* name) {
67 Mutex* mu = new Mutex(name);
68 int result = pthread_mutex_init(&mu->lock_impl_, NULL);
Ian Rogersb033c752011-07-20 12:22:35 -070069 CHECK_EQ(0, result);
Carl Shapirob5573532011-07-12 18:22:59 -070070 return mu;
71}
72
73void Mutex::Lock() {
74 int result = pthread_mutex_lock(&lock_impl_);
75 CHECK_EQ(result, 0);
76 SetOwner(Thread::Current());
77}
78
79bool Mutex::TryLock() {
80 int result = pthread_mutex_lock(&lock_impl_);
81 if (result == EBUSY) {
82 return false;
83 } else {
84 CHECK_EQ(result, 0);
85 SetOwner(Thread::Current());
86 return true;
87 }
88}
89
90void Mutex::Unlock() {
91 CHECK(GetOwner() == Thread::Current());
92 int result = pthread_mutex_unlock(&lock_impl_);
93 CHECK_EQ(result, 0);
Elliott Hughesf4c21c92011-08-19 17:31:31 -070094 SetOwner(NULL);
Carl Shapirob5573532011-07-12 18:22:59 -070095}
96
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -070097void Frame::Next() {
98 byte* next_sp = reinterpret_cast<byte*>(sp_) +
99 GetMethod()->GetFrameSize();
100 sp_ = reinterpret_cast<const Method**>(next_sp);
101}
102
103void* Frame::GetPC() const {
104 byte* pc_addr = reinterpret_cast<byte*>(sp_) +
Ian Rogers762400c2011-08-23 12:14:16 -0700105 GetMethod()->GetReturnPcOffset();
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -0700106 return reinterpret_cast<void*>(pc_addr);
107}
108
109const Method* Frame::NextMethod() const {
110 byte* next_sp = reinterpret_cast<byte*>(sp_) +
111 GetMethod()->GetFrameSize();
112 return reinterpret_cast<const Method*>(next_sp);
113}
114
Carl Shapiro61e019d2011-07-14 16:53:09 -0700115void* ThreadStart(void *arg) {
Elliott Hughes53b61312011-08-12 18:28:20 -0700116 UNIMPLEMENTED(FATAL);
Carl Shapirob5573532011-07-12 18:22:59 -0700117 return NULL;
118}
119
Brian Carlstromb765be02011-08-17 23:54:10 -0700120Thread* Thread::Create(const Runtime* runtime) {
121 size_t stack_size = runtime->GetStackSize();
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700122 scoped_ptr<MemMap> stack(MemMap::Map(stack_size, PROT_READ | PROT_WRITE));
Brian Carlstromb765be02011-08-17 23:54:10 -0700123 if (stack == NULL) {
124 LOG(FATAL) << "failed to allocate thread stack";
125 // notreached
126 return NULL;
Carl Shapiro61e019d2011-07-14 16:53:09 -0700127 }
128
129 Thread* new_thread = new Thread;
Ian Rogers176f59c2011-07-20 13:14:11 -0700130 new_thread->InitCpu();
Brian Carlstromb765be02011-08-17 23:54:10 -0700131 new_thread->stack_.reset(stack.release());
132 // Since stacks are assumed to grown downward the base is the limit and the limit is the base.
133 new_thread->stack_limit_ = stack->GetAddress();
134 new_thread->stack_base_ = stack->GetLimit();
Carl Shapiro61e019d2011-07-14 16:53:09 -0700135
136 pthread_attr_t attr;
137 int result = pthread_attr_init(&attr);
138 CHECK_EQ(result, 0);
139
140 result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
141 CHECK_EQ(result, 0);
142
143 pthread_t handle;
144 result = pthread_create(&handle, &attr, ThreadStart, new_thread);
145 CHECK_EQ(result, 0);
146
147 result = pthread_attr_destroy(&attr);
148 CHECK_EQ(result, 0);
149
150 return new_thread;
151}
152
Elliott Hughes515a5bc2011-08-17 11:08:34 -0700153Thread* Thread::Attach(const Runtime* runtime) {
Carl Shapiro61e019d2011-07-14 16:53:09 -0700154 Thread* thread = new Thread;
Ian Rogers176f59c2011-07-20 13:14:11 -0700155 thread->InitCpu();
Carl Shapiro61e019d2011-07-14 16:53:09 -0700156 thread->stack_limit_ = reinterpret_cast<byte*>(-1); // TODO: getrlimit
157 uintptr_t addr = reinterpret_cast<uintptr_t>(&thread); // TODO: ask pthreads
Brian Carlstromb0460ea2011-07-29 10:08:05 -0700158 uintptr_t stack_base = RoundUp(addr, kPageSize);
Carl Shapiro61e019d2011-07-14 16:53:09 -0700159 thread->stack_base_ = reinterpret_cast<byte*>(stack_base);
160 // TODO: set the stack size
161
162 thread->handle_ = pthread_self();
163
164 thread->state_ = kRunnable;
165
Elliott Hughesa5780da2011-07-17 11:39:39 -0700166 errno = pthread_setspecific(Thread::pthread_key_self_, thread);
167 if (errno != 0) {
168 PLOG(FATAL) << "pthread_setspecific failed";
169 }
170
Elliott Hughes0af55432011-08-17 18:37:28 -0700171 JavaVMExt* vm = runtime->GetJavaVM();
Elliott Hughes515a5bc2011-08-17 11:08:34 -0700172 CHECK(vm != NULL);
173 bool check_jni = vm->check_jni;
174 thread->jni_env_ = reinterpret_cast<JNIEnv*>(new JNIEnvExt(thread, check_jni));
Elliott Hughes330304d2011-08-12 14:28:05 -0700175
Carl Shapiro61e019d2011-07-14 16:53:09 -0700176 return thread;
177}
178
Carl Shapirob5573532011-07-12 18:22:59 -0700179static void ThreadExitCheck(void* arg) {
180 LG << "Thread exit check";
181}
182
183bool Thread::Init() {
184 // Allocate a TLS slot.
185 if (pthread_key_create(&Thread::pthread_key_self_, ThreadExitCheck) != 0) {
Elliott Hugheseb4f6142011-07-15 17:43:51 -0700186 PLOG(WARNING) << "pthread_key_create failed";
Carl Shapirob5573532011-07-12 18:22:59 -0700187 return false;
188 }
189
190 // Double-check the TLS slot allocation.
191 if (pthread_getspecific(pthread_key_self_) != NULL) {
Elliott Hugheseb4f6142011-07-15 17:43:51 -0700192 LOG(WARNING) << "newly-created pthread TLS slot is not NULL";
Carl Shapirob5573532011-07-12 18:22:59 -0700193 return false;
194 }
195
196 // TODO: initialize other locks and condition variables
197
198 return true;
199}
200
Ian Rogersa8cd9f42011-08-19 16:43:41 -0700201size_t Thread::NumShbHandles() {
202 size_t count = 0;
203 for (StackHandleBlock* cur = top_shb_; cur; cur = cur->Link()) {
204 count += cur->NumberOfReferences();
205 }
206 return count;
207}
208
209bool Thread::ShbContains(jobject obj) {
Brian Carlstrom4873d462011-08-21 15:23:39 -0700210 Object** shb_entry = reinterpret_cast<Object**>(obj);
Ian Rogersa8cd9f42011-08-19 16:43:41 -0700211 for (StackHandleBlock* cur = top_shb_; cur; cur = cur->Link()) {
212 size_t num_refs = cur->NumberOfReferences();
213 DCHECK_GT(num_refs, 0u); // A SHB should always have a jobject/jclass
214 if ((&cur->Handles()[0] >= shb_entry) &&
215 (shb_entry <= (&cur->Handles()[num_refs-1]))) {
216 return true;
217 }
218 }
219 return false;
220}
221
Elliott Hughese5b0dc82011-08-23 09:59:02 -0700222void Thread::ThrowNewException(const char* exception_class_descriptor, const char* fmt, ...) {
Elliott Hughes37f7a402011-08-22 18:56:01 -0700223 std::string msg;
Elliott Hughesa5b897e2011-08-16 11:33:06 -0700224 va_list args;
225 va_start(args, fmt);
Elliott Hughes37f7a402011-08-22 18:56:01 -0700226 StringAppendV(&msg, fmt, args);
Elliott Hughesa5b897e2011-08-16 11:33:06 -0700227 va_end(args);
Elliott Hughes37f7a402011-08-22 18:56:01 -0700228
Elliott Hughese5b0dc82011-08-23 09:59:02 -0700229 // Convert "Ljava/lang/Exception;" into JNI-style "java/lang/Exception".
230 CHECK(exception_class_descriptor[0] == 'L');
231 std::string descriptor(exception_class_descriptor + 1);
232 CHECK(descriptor[descriptor.length() - 1] == ';');
233 descriptor.erase(descriptor.length() - 1);
234
235 JNIEnv* env = GetJniEnv();
236 jclass exception_class = env->FindClass(descriptor.c_str());
237 CHECK(exception_class != NULL) << "descriptor=\"" << descriptor << "\"";
238 int rc = env->ThrowNew(exception_class, msg.c_str());
239 CHECK_EQ(rc, JNI_OK);
Elliott Hughesa5b897e2011-08-16 11:33:06 -0700240}
241
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -0700242Frame Thread::FindExceptionHandler(void* throw_pc, void** handler_pc) {
243 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
244 DCHECK(class_linker != NULL);
245
246 Frame cur_frame = GetTopOfStack();
247 for (int unwind_depth = 0; ; unwind_depth++) {
248 const Method* cur_method = cur_frame.GetMethod();
249 DexCache* dex_cache = cur_method->GetDeclaringClass()->GetDexCache();
250 const DexFile& dex_file = class_linker->FindDexFile(dex_cache);
251
252 void* handler_addr = FindExceptionHandlerInMethod(cur_method,
253 throw_pc,
254 dex_file,
255 class_linker);
256 if (handler_addr) {
257 *handler_pc = handler_addr;
258 return cur_frame;
259 } else {
260 // Check if we are at the last frame
261 if (cur_frame.HasNext()) {
262 cur_frame.Next();
263 } else {
264 // Either at the top of stack or next frame is native.
265 break;
266 }
267 }
268 }
269 *handler_pc = NULL;
270 return Frame();
271}
272
273void* Thread::FindExceptionHandlerInMethod(const Method* method,
274 void* throw_pc,
275 const DexFile& dex_file,
276 ClassLinker* class_linker) {
Elliott Hughese5b0dc82011-08-23 09:59:02 -0700277 Throwable* exception_obj = exception_;
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -0700278 exception_ = NULL;
279
280 intptr_t dex_pc = -1;
281 const DexFile::CodeItem* code_item = dex_file.GetCodeItem(method->code_off_);
282 DexFile::CatchHandlerIterator iter;
283 for (iter = dex_file.dexFindCatchHandler(*code_item,
284 method->ToDexPC(reinterpret_cast<intptr_t>(throw_pc)));
285 !iter.HasNext();
286 iter.Next()) {
287 Class* klass = class_linker->FindSystemClass(dex_file.dexStringByTypeIdx(iter.Get().type_idx_));
288 DCHECK(klass != NULL);
289 if (exception_obj->InstanceOf(klass)) {
290 dex_pc = iter.Get().address_;
291 break;
292 }
293 }
294
295 exception_ = exception_obj;
296 if (iter.HasNext()) {
297 return NULL;
298 } else {
299 return reinterpret_cast<void*>( method->ToNativePC(dex_pc) );
300 }
301}
302
Ian Rogersb033c752011-07-20 12:22:35 -0700303static const char* kStateNames[] = {
304 "New",
305 "Runnable",
306 "Blocked",
307 "Waiting",
308 "TimedWaiting",
309 "Native",
310 "Terminated",
311};
312std::ostream& operator<<(std::ostream& os, const Thread::State& state) {
313 if (state >= Thread::kNew && state <= Thread::kTerminated) {
314 os << kStateNames[state-Thread::kNew];
315 } else {
316 os << "State[" << static_cast<int>(state) << "]";
317 }
318 return os;
319}
320
Elliott Hughes330304d2011-08-12 14:28:05 -0700321std::ostream& operator<<(std::ostream& os, const Thread& thread) {
322 os << "Thread[" << &thread
323 << ",id=" << thread.GetId()
324 << ",tid=" << thread.GetNativeId()
325 << ",state=" << thread.GetState() << "]";
326 return os;
327}
328
Carl Shapiro61e019d2011-07-14 16:53:09 -0700329ThreadList* ThreadList::Create() {
330 return new ThreadList;
331}
332
Carl Shapirob5573532011-07-12 18:22:59 -0700333ThreadList::ThreadList() {
334 lock_ = Mutex::Create("ThreadList::Lock");
335}
336
337ThreadList::~ThreadList() {
338 // Make sure that all threads have exited and unregistered when we
339 // reach this point. This means that all daemon threads had been
340 // shutdown cleanly.
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700341 CHECK_LE(list_.size(), 1U);
Carl Shapiro7a909592011-07-24 19:21:59 -0700342 // TODO: wait for all other threads to unregister
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700343 CHECK(list_.size() == 0 || list_.front() == Thread::Current());
Carl Shapiro7a909592011-07-24 19:21:59 -0700344 // TODO: detach the current thread
Carl Shapirob5573532011-07-12 18:22:59 -0700345 delete lock_;
346 lock_ = NULL;
347}
348
349void ThreadList::Register(Thread* thread) {
350 MutexLock mu(lock_);
351 CHECK(find(list_.begin(), list_.end(), thread) == list_.end());
352 list_.push_front(thread);
353}
354
355void ThreadList::Unregister(Thread* thread) {
356 MutexLock mu(lock_);
357 CHECK(find(list_.begin(), list_.end(), thread) != list_.end());
358 list_.remove(thread);
359}
360
Carl Shapirob5573532011-07-12 18:22:59 -0700361} // namespace