blob: 5fdff78f4e961f2ab8fbc15e132acae9049a383e [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"
Ian Rogers408f79a2011-08-23 18:22:33 -070012#include "heap.h"
Elliott Hughesc5f7c912011-08-18 14:00:42 -070013#include "jni_internal.h"
Elliott Hughesa5b897e2011-08-16 11:33:06 -070014#include "object.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070015#include "runtime.h"
16#include "utils.h"
buzbee54330722011-08-23 16:46:55 -070017#include "runtime_support.h"
Carl Shapirob5573532011-07-12 18:22:59 -070018
19namespace art {
20
Elliott Hughese27955c2011-08-26 15:21:24 -070021/* desktop Linux needs a little help with gettid() */
22#if !defined(HAVE_ANDROID_OS)
23#define __KERNEL__
24# include <linux/unistd.h>
25#ifdef _syscall0
26_syscall0(pid_t, gettid)
27#else
28pid_t gettid() { return syscall(__NR_gettid);}
29#endif
30#undef __KERNEL__
31#endif
32
Carl Shapirob5573532011-07-12 18:22:59 -070033pthread_key_t Thread::pthread_key_self_;
34
buzbee3ea4ec52011-08-22 17:37:19 -070035void Thread::InitFunctionPointers() {
buzbee54330722011-08-23 16:46:55 -070036#if defined(__arm__)
37 pShlLong = art_shl_long;
38 pShrLong = art_shr_long;
39 pUshrLong = art_ushr_long;
buzbee7b1b86d2011-08-26 18:59:10 -070040 pIdiv = __aeabi_idiv;
41 pIdivmod = __aeabi_idivmod;
42 pI2f = __aeabi_i2f;
43 pF2iz = __aeabi_f2iz;
44 pD2f = __aeabi_d2f;
45 pF2d = __aeabi_f2d;
46 pD2iz = __aeabi_d2iz;
47 pL2f = __aeabi_l2f;
48 pL2d = __aeabi_l2d;
49 pFadd = __aeabi_fadd;
50 pFsub = __aeabi_fsub;
51 pFdiv = __aeabi_fdiv;
52 pFmul = __aeabi_fmul;
53 pFmodf = fmodf;
54 pDadd = __aeabi_dadd;
55 pDsub = __aeabi_dsub;
56 pDdiv = __aeabi_ddiv;
57 pDmul = __aeabi_dmul;
58 pFmod = fmod;
59 pArtF2l = artF2L;
60 pArtD2l = artD2L;
61 pLdivmod = __aeabi_ldivmod;
buzbee439c4fa2011-08-27 15:59:07 -070062 pLmul = __aeabi_lmul;
buzbee54330722011-08-23 16:46:55 -070063#endif
buzbee3ea4ec52011-08-22 17:37:19 -070064 pArtAllocArrayByClass = Array::Alloc;
65 pMemcpy = memcpy;
buzbeee6d61962011-08-27 11:58:19 -070066 pArtHandleFillArrayDataNoThrow = artHandleFillArrayDataNoThrow;
buzbee3ea4ec52011-08-22 17:37:19 -070067#if 0
buzbee3ea4ec52011-08-22 17:37:19 -070068bool (Thread::*pArtUnlockObject)(struct Thread*, struct Object*);
69bool (Thread::*pArtCanPutArrayElementNoThrow)(const struct ClassObject*,
70 const struct ClassObject*);
71int (Thread::*pArtInstanceofNonTrivialNoThrow)
72 (const struct ClassObject*, const struct ClassObject*);
73int (Thread::*pArtInstanceofNonTrivial) (const struct ClassObject*,
74 const struct ClassObject*);
75struct Method* (Thread::*pArtFindInterfaceMethodInCache)(ClassObject*, uint32_t,
76 const struct Method*, struct DvmDex*);
77bool (Thread::*pArtUnlockObjectNoThrow)(struct Thread*, struct Object*);
78void (Thread::*pArtLockObjectNoThrow)(struct Thread*, struct Object*);
79struct Object* (Thread::*pArtAllocObjectNoThrow)(struct ClassObject*, int);
80void (Thread::*pArtThrowException)(struct Thread*, struct Object*);
81bool (Thread::*pArtHandleFillArrayDataNoThrow)(struct ArrayObject*, const uint16_t*);
82#endif
83}
84
Carl Shapirob5573532011-07-12 18:22:59 -070085Mutex* Mutex::Create(const char* name) {
86 Mutex* mu = new Mutex(name);
87 int result = pthread_mutex_init(&mu->lock_impl_, NULL);
Ian Rogersb033c752011-07-20 12:22:35 -070088 CHECK_EQ(0, result);
Carl Shapirob5573532011-07-12 18:22:59 -070089 return mu;
90}
91
92void Mutex::Lock() {
93 int result = pthread_mutex_lock(&lock_impl_);
94 CHECK_EQ(result, 0);
95 SetOwner(Thread::Current());
96}
97
98bool Mutex::TryLock() {
99 int result = pthread_mutex_lock(&lock_impl_);
100 if (result == EBUSY) {
101 return false;
102 } else {
103 CHECK_EQ(result, 0);
104 SetOwner(Thread::Current());
105 return true;
106 }
107}
108
109void Mutex::Unlock() {
110 CHECK(GetOwner() == Thread::Current());
111 int result = pthread_mutex_unlock(&lock_impl_);
112 CHECK_EQ(result, 0);
Elliott Hughesf4c21c92011-08-19 17:31:31 -0700113 SetOwner(NULL);
Carl Shapirob5573532011-07-12 18:22:59 -0700114}
115
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -0700116void Frame::Next() {
117 byte* next_sp = reinterpret_cast<byte*>(sp_) +
Shih-wei Liaod11af152011-08-23 16:02:11 -0700118 GetMethod()->GetFrameSizeInBytes();
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -0700119 sp_ = reinterpret_cast<const Method**>(next_sp);
120}
121
Shih-wei Liao55df06b2011-08-26 14:39:27 -0700122uintptr_t Frame::GetPC() const {
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -0700123 byte* pc_addr = reinterpret_cast<byte*>(sp_) +
Shih-wei Liaod11af152011-08-23 16:02:11 -0700124 GetMethod()->GetReturnPcOffsetInBytes();
Shih-wei Liao55df06b2011-08-26 14:39:27 -0700125 return *reinterpret_cast<uintptr_t*>(pc_addr);
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -0700126}
127
128const Method* Frame::NextMethod() const {
129 byte* next_sp = reinterpret_cast<byte*>(sp_) +
Shih-wei Liaod11af152011-08-23 16:02:11 -0700130 GetMethod()->GetFrameSizeInBytes();
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -0700131 return reinterpret_cast<const Method*>(next_sp);
132}
133
Carl Shapiro61e019d2011-07-14 16:53:09 -0700134void* ThreadStart(void *arg) {
Elliott Hughes53b61312011-08-12 18:28:20 -0700135 UNIMPLEMENTED(FATAL);
Carl Shapirob5573532011-07-12 18:22:59 -0700136 return NULL;
137}
138
Brian Carlstromb765be02011-08-17 23:54:10 -0700139Thread* Thread::Create(const Runtime* runtime) {
140 size_t stack_size = runtime->GetStackSize();
Carl Shapiro61e019d2011-07-14 16:53:09 -0700141
142 Thread* new_thread = new Thread;
Ian Rogers176f59c2011-07-20 13:14:11 -0700143 new_thread->InitCpu();
Carl Shapiro61e019d2011-07-14 16:53:09 -0700144
145 pthread_attr_t attr;
Elliott Hughese27955c2011-08-26 15:21:24 -0700146 errno = pthread_attr_init(&attr);
147 if (errno != 0) {
148 PLOG(FATAL) << "pthread_attr_init failed";
149 }
Carl Shapiro61e019d2011-07-14 16:53:09 -0700150
Elliott Hughese27955c2011-08-26 15:21:24 -0700151 errno = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
152 if (errno != 0) {
153 PLOG(FATAL) << "pthread_attr_setdetachstate(PTHREAD_CREATE_DETACHED) failed";
154 }
Carl Shapiro61e019d2011-07-14 16:53:09 -0700155
Elliott Hughese27955c2011-08-26 15:21:24 -0700156 errno = pthread_attr_setstacksize(&attr, stack_size);
157 if (errno != 0) {
158 PLOG(FATAL) << "pthread_attr_setstacksize(" << stack_size << ") failed";
159 }
Carl Shapiro61e019d2011-07-14 16:53:09 -0700160
Elliott Hughese27955c2011-08-26 15:21:24 -0700161 errno = pthread_create(&new_thread->handle_, &attr, ThreadStart, new_thread);
162 if (errno != 0) {
163 PLOG(FATAL) << "pthread_create failed";
164 }
165
166 errno = pthread_attr_destroy(&attr);
167 if (errno != 0) {
168 PLOG(FATAL) << "pthread_attr_destroy failed";
169 }
Carl Shapiro61e019d2011-07-14 16:53:09 -0700170
171 return new_thread;
172}
173
Elliott Hughes515a5bc2011-08-17 11:08:34 -0700174Thread* Thread::Attach(const Runtime* runtime) {
Carl Shapiro61e019d2011-07-14 16:53:09 -0700175 Thread* thread = new Thread;
Ian Rogers176f59c2011-07-20 13:14:11 -0700176 thread->InitCpu();
Carl Shapiro61e019d2011-07-14 16:53:09 -0700177
178 thread->handle_ = pthread_self();
179
180 thread->state_ = kRunnable;
181
Elliott Hughesa5780da2011-07-17 11:39:39 -0700182 errno = pthread_setspecific(Thread::pthread_key_self_, thread);
183 if (errno != 0) {
Elliott Hughesc1674ed2011-08-25 18:09:09 -0700184 PLOG(FATAL) << "pthread_setspecific failed";
Elliott Hughesa5780da2011-07-17 11:39:39 -0700185 }
186
Elliott Hughes75770752011-08-24 17:52:38 -0700187 thread->jni_env_ = new JNIEnvExt(thread, runtime->GetJavaVM());
Elliott Hughes330304d2011-08-12 14:28:05 -0700188
Carl Shapiro61e019d2011-07-14 16:53:09 -0700189 return thread;
190}
191
Elliott Hughese27955c2011-08-26 15:21:24 -0700192pid_t Thread::GetTid() const {
193 return gettid();
194}
195
Carl Shapirob5573532011-07-12 18:22:59 -0700196static void ThreadExitCheck(void* arg) {
197 LG << "Thread exit check";
198}
199
Elliott Hughesc1674ed2011-08-25 18:09:09 -0700200bool Thread::Startup() {
Carl Shapirob5573532011-07-12 18:22:59 -0700201 // Allocate a TLS slot.
Elliott Hughesc1674ed2011-08-25 18:09:09 -0700202 errno = pthread_key_create(&Thread::pthread_key_self_, ThreadExitCheck);
203 if (errno != 0) {
Elliott Hugheseb4f6142011-07-15 17:43:51 -0700204 PLOG(WARNING) << "pthread_key_create failed";
Carl Shapirob5573532011-07-12 18:22:59 -0700205 return false;
206 }
207
208 // Double-check the TLS slot allocation.
209 if (pthread_getspecific(pthread_key_self_) != NULL) {
Elliott Hugheseb4f6142011-07-15 17:43:51 -0700210 LOG(WARNING) << "newly-created pthread TLS slot is not NULL";
Carl Shapirob5573532011-07-12 18:22:59 -0700211 return false;
212 }
213
214 // TODO: initialize other locks and condition variables
215
216 return true;
217}
218
Elliott Hughesc1674ed2011-08-25 18:09:09 -0700219void Thread::Shutdown() {
220 errno = pthread_key_delete(Thread::pthread_key_self_);
221 if (errno != 0) {
222 PLOG(WARNING) << "pthread_key_delete failed";
223 }
224}
225
226Thread::~Thread() {
227 delete jni_env_;
228}
229
Ian Rogers408f79a2011-08-23 18:22:33 -0700230size_t Thread::NumSirtReferences() {
Ian Rogersa8cd9f42011-08-19 16:43:41 -0700231 size_t count = 0;
Ian Rogers408f79a2011-08-23 18:22:33 -0700232 for (StackIndirectReferenceTable* cur = top_sirt_; cur; cur = cur->Link()) {
Ian Rogersa8cd9f42011-08-19 16:43:41 -0700233 count += cur->NumberOfReferences();
234 }
235 return count;
236}
237
Ian Rogers408f79a2011-08-23 18:22:33 -0700238bool Thread::SirtContains(jobject obj) {
239 Object** sirt_entry = reinterpret_cast<Object**>(obj);
240 for (StackIndirectReferenceTable* cur = top_sirt_; cur; cur = cur->Link()) {
Ian Rogersa8cd9f42011-08-19 16:43:41 -0700241 size_t num_refs = cur->NumberOfReferences();
Ian Rogers408f79a2011-08-23 18:22:33 -0700242 // A SIRT should always have a jobject/jclass as a native method is passed
243 // in a this pointer or a class
244 DCHECK_GT(num_refs, 0u);
245 if ((&cur->References()[0] >= sirt_entry) &&
246 (sirt_entry <= (&cur->References()[num_refs-1]))) {
Ian Rogersa8cd9f42011-08-19 16:43:41 -0700247 return true;
248 }
249 }
250 return false;
251}
252
Ian Rogers408f79a2011-08-23 18:22:33 -0700253Object* Thread::DecodeJObject(jobject obj) {
254 // TODO: Only allowed to hold Object* when in the runnable state
255 // DCHECK(state_ == kRunnable);
256 if (obj == NULL) {
257 return NULL;
258 }
259 IndirectRef ref = reinterpret_cast<IndirectRef>(obj);
260 IndirectRefKind kind = GetIndirectRefKind(ref);
261 Object* result;
262 switch (kind) {
263 case kLocal:
264 {
Elliott Hughes69f5bc62011-08-24 09:26:14 -0700265 IndirectReferenceTable& locals = jni_env_->locals;
Ian Rogers408f79a2011-08-23 18:22:33 -0700266 result = locals.Get(ref);
267 break;
268 }
269 case kGlobal:
270 {
271 JavaVMExt* vm = Runtime::Current()->GetJavaVM();
272 IndirectReferenceTable& globals = vm->globals;
273 MutexLock mu(vm->globals_lock);
274 result = globals.Get(ref);
275 break;
276 }
277 case kWeakGlobal:
278 {
279 JavaVMExt* vm = Runtime::Current()->GetJavaVM();
280 IndirectReferenceTable& weak_globals = vm->weak_globals;
281 MutexLock mu(vm->weak_globals_lock);
282 result = weak_globals.Get(ref);
283 if (result == kClearedJniWeakGlobal) {
284 // This is a special case where it's okay to return NULL.
285 return NULL;
286 }
287 break;
288 }
289 case kSirtOrInvalid:
290 default:
291 // TODO: make stack indirect reference table lookup more efficient
292 // Check if this is a local reference in the SIRT
293 if (SirtContains(obj)) {
294 result = *reinterpret_cast<Object**>(obj); // Read from SIRT
295 } else if (false /*gDvmJni.workAroundAppJniBugs*/) { // TODO
296 // Assume an invalid local reference is actually a direct pointer.
297 result = reinterpret_cast<Object*>(obj);
298 } else {
299 LOG(FATAL) << "Invalid indirect reference " << obj;
300 result = reinterpret_cast<Object*>(kInvalidIndirectRefObject);
301 }
302 }
303
304 if (result == NULL) {
305 LOG(FATAL) << "JNI ERROR (app bug): use of deleted " << kind << ": "
306 << obj;
307 }
308 Heap::VerifyObject(result);
309 return result;
310}
311
Shih-wei Liao55df06b2011-08-26 14:39:27 -0700312// TODO: Replaces trace.method and trace.pc with IntArray nad
313// ObjectArray<Method>.
314Thread::InternalStackTrace* Thread::GetStackTrace(uint16_t length) {
315 Frame frame = Thread::Current()->GetTopOfStack();
316 InternalStackTrace *traces = new InternalStackTrace[length];
317 for (uint16_t i = 0; i < length && frame.HasNext(); ++i, frame.Next()) {
318 traces[i].method = frame.GetMethod();
319 traces[i].pc = frame.GetPC();
320 }
321 return traces;
322}
323
324ObjectArray<StackTraceElement>* Thread::GetStackTraceElement(uint16_t length, InternalStackTrace *raw_trace) {
325 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
326 ObjectArray<StackTraceElement>* java_traces = class_linker->AllocStackTraceElementArray(length);
327
328 for (uint16_t i = 0; i < length; ++i) {
329 // Prepare parameter for StackTraceElement(String cls, String method, String file, int line)
330 const Method* method = raw_trace[i].method;
331 const Class* klass = method->GetDeclaringClass();
332 const DexFile& dex_file = class_linker->FindDexFile(klass->GetDexCache());
333 String* readable_descriptor = String::AllocFromModifiedUtf8(PrettyDescriptor(klass->GetDescriptor()).c_str());
334
335 StackTraceElement* obj =
336 StackTraceElement::Alloc(readable_descriptor,
337 method->GetName(), String::AllocFromModifiedUtf8(klass->source_file_),
338 dex_file.GetLineNumFromPC(method, method->ToDexPC(raw_trace[i].pc)));
339 java_traces->Set(i, obj);
340 }
341 return java_traces;
342}
343
Elliott Hughese5b0dc82011-08-23 09:59:02 -0700344void Thread::ThrowNewException(const char* exception_class_descriptor, const char* fmt, ...) {
Elliott Hughes37f7a402011-08-22 18:56:01 -0700345 std::string msg;
Elliott Hughesa5b897e2011-08-16 11:33:06 -0700346 va_list args;
347 va_start(args, fmt);
Elliott Hughes37f7a402011-08-22 18:56:01 -0700348 StringAppendV(&msg, fmt, args);
Elliott Hughesa5b897e2011-08-16 11:33:06 -0700349 va_end(args);
Elliott Hughes37f7a402011-08-22 18:56:01 -0700350
Elliott Hughese5b0dc82011-08-23 09:59:02 -0700351 // Convert "Ljava/lang/Exception;" into JNI-style "java/lang/Exception".
352 CHECK(exception_class_descriptor[0] == 'L');
353 std::string descriptor(exception_class_descriptor + 1);
354 CHECK(descriptor[descriptor.length() - 1] == ';');
355 descriptor.erase(descriptor.length() - 1);
356
357 JNIEnv* env = GetJniEnv();
358 jclass exception_class = env->FindClass(descriptor.c_str());
359 CHECK(exception_class != NULL) << "descriptor=\"" << descriptor << "\"";
360 int rc = env->ThrowNew(exception_class, msg.c_str());
361 CHECK_EQ(rc, JNI_OK);
Elliott Hughesa5b897e2011-08-16 11:33:06 -0700362}
363
Elliott Hughes79082e32011-08-25 12:07:32 -0700364void Thread::ThrowOutOfMemoryError() {
365 UNIMPLEMENTED(FATAL);
366}
367
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -0700368Frame Thread::FindExceptionHandler(void* throw_pc, void** handler_pc) {
369 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
370 DCHECK(class_linker != NULL);
371
372 Frame cur_frame = GetTopOfStack();
373 for (int unwind_depth = 0; ; unwind_depth++) {
374 const Method* cur_method = cur_frame.GetMethod();
375 DexCache* dex_cache = cur_method->GetDeclaringClass()->GetDexCache();
376 const DexFile& dex_file = class_linker->FindDexFile(dex_cache);
377
378 void* handler_addr = FindExceptionHandlerInMethod(cur_method,
379 throw_pc,
380 dex_file,
381 class_linker);
382 if (handler_addr) {
383 *handler_pc = handler_addr;
384 return cur_frame;
385 } else {
386 // Check if we are at the last frame
387 if (cur_frame.HasNext()) {
388 cur_frame.Next();
389 } else {
390 // Either at the top of stack or next frame is native.
391 break;
392 }
393 }
394 }
395 *handler_pc = NULL;
396 return Frame();
397}
398
399void* Thread::FindExceptionHandlerInMethod(const Method* method,
400 void* throw_pc,
401 const DexFile& dex_file,
402 ClassLinker* class_linker) {
Elliott Hughese5b0dc82011-08-23 09:59:02 -0700403 Throwable* exception_obj = exception_;
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -0700404 exception_ = NULL;
405
406 intptr_t dex_pc = -1;
407 const DexFile::CodeItem* code_item = dex_file.GetCodeItem(method->code_off_);
408 DexFile::CatchHandlerIterator iter;
409 for (iter = dex_file.dexFindCatchHandler(*code_item,
410 method->ToDexPC(reinterpret_cast<intptr_t>(throw_pc)));
411 !iter.HasNext();
412 iter.Next()) {
413 Class* klass = class_linker->FindSystemClass(dex_file.dexStringByTypeIdx(iter.Get().type_idx_));
414 DCHECK(klass != NULL);
415 if (exception_obj->InstanceOf(klass)) {
416 dex_pc = iter.Get().address_;
417 break;
418 }
419 }
420
421 exception_ = exception_obj;
422 if (iter.HasNext()) {
423 return NULL;
424 } else {
425 return reinterpret_cast<void*>( method->ToNativePC(dex_pc) );
426 }
427}
428
Ian Rogersb033c752011-07-20 12:22:35 -0700429static const char* kStateNames[] = {
430 "New",
431 "Runnable",
432 "Blocked",
433 "Waiting",
434 "TimedWaiting",
435 "Native",
436 "Terminated",
437};
438std::ostream& operator<<(std::ostream& os, const Thread::State& state) {
439 if (state >= Thread::kNew && state <= Thread::kTerminated) {
440 os << kStateNames[state-Thread::kNew];
441 } else {
442 os << "State[" << static_cast<int>(state) << "]";
443 }
444 return os;
445}
446
Elliott Hughes330304d2011-08-12 14:28:05 -0700447std::ostream& operator<<(std::ostream& os, const Thread& thread) {
448 os << "Thread[" << &thread
Elliott Hughese27955c2011-08-26 15:21:24 -0700449 << ",pthread_t=" << thread.GetImpl()
450 << ",tid=" << thread.GetTid()
451 << ",id=" << thread.GetId()
452 << ",state=" << thread.GetState() << "]";
Elliott Hughes330304d2011-08-12 14:28:05 -0700453 return os;
454}
455
Carl Shapiro61e019d2011-07-14 16:53:09 -0700456ThreadList* ThreadList::Create() {
457 return new ThreadList;
458}
459
Carl Shapirob5573532011-07-12 18:22:59 -0700460ThreadList::ThreadList() {
461 lock_ = Mutex::Create("ThreadList::Lock");
462}
463
464ThreadList::~ThreadList() {
Elliott Hughesc1674ed2011-08-25 18:09:09 -0700465 if (Contains(Thread::Current())) {
466 Runtime::Current()->DetachCurrentThread();
467 }
468
469 // All threads should have exited and unregistered when we
Carl Shapirob5573532011-07-12 18:22:59 -0700470 // reach this point. This means that all daemon threads had been
471 // shutdown cleanly.
Elliott Hughesc1674ed2011-08-25 18:09:09 -0700472 // TODO: dump ThreadList if non-empty.
473 CHECK_EQ(list_.size(), 0U);
474
Carl Shapirob5573532011-07-12 18:22:59 -0700475 delete lock_;
476 lock_ = NULL;
477}
478
Elliott Hughesc1674ed2011-08-25 18:09:09 -0700479bool ThreadList::Contains(Thread* thread) {
480 return find(list_.begin(), list_.end(), thread) != list_.end();
481}
482
Carl Shapirob5573532011-07-12 18:22:59 -0700483void ThreadList::Register(Thread* thread) {
484 MutexLock mu(lock_);
Elliott Hughesc1674ed2011-08-25 18:09:09 -0700485 CHECK(!Contains(thread));
Carl Shapirob5573532011-07-12 18:22:59 -0700486 list_.push_front(thread);
487}
488
489void ThreadList::Unregister(Thread* thread) {
490 MutexLock mu(lock_);
Elliott Hughesc1674ed2011-08-25 18:09:09 -0700491 CHECK(Contains(thread));
Carl Shapirob5573532011-07-12 18:22:59 -0700492 list_.remove(thread);
493}
494
Carl Shapirob5573532011-07-12 18:22:59 -0700495} // namespace