blob: b48f60028fac7658825911a7d12717ff3274173a [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
buzbeedfd3d702011-08-28 12:56:51 -070064 pAllocFromCode = Array::AllocFromCode;
65 pNewInstanceFromCode = Class::NewInstanceFromCode;
buzbee3ea4ec52011-08-22 17:37:19 -070066 pMemcpy = memcpy;
buzbeee6d61962011-08-27 11:58:19 -070067 pArtHandleFillArrayDataNoThrow = artHandleFillArrayDataNoThrow;
buzbee3ea4ec52011-08-22 17:37:19 -070068#if 0
buzbee3ea4ec52011-08-22 17:37:19 -070069bool (Thread::*pArtUnlockObject)(struct Thread*, struct Object*);
70bool (Thread::*pArtCanPutArrayElementNoThrow)(const struct ClassObject*,
71 const struct ClassObject*);
72int (Thread::*pArtInstanceofNonTrivialNoThrow)
73 (const struct ClassObject*, const struct ClassObject*);
74int (Thread::*pArtInstanceofNonTrivial) (const struct ClassObject*,
75 const struct ClassObject*);
76struct Method* (Thread::*pArtFindInterfaceMethodInCache)(ClassObject*, uint32_t,
77 const struct Method*, struct DvmDex*);
78bool (Thread::*pArtUnlockObjectNoThrow)(struct Thread*, struct Object*);
79void (Thread::*pArtLockObjectNoThrow)(struct Thread*, struct Object*);
80struct Object* (Thread::*pArtAllocObjectNoThrow)(struct ClassObject*, int);
81void (Thread::*pArtThrowException)(struct Thread*, struct Object*);
82bool (Thread::*pArtHandleFillArrayDataNoThrow)(struct ArrayObject*, const uint16_t*);
83#endif
84}
85
Carl Shapirob5573532011-07-12 18:22:59 -070086Mutex* Mutex::Create(const char* name) {
87 Mutex* mu = new Mutex(name);
88 int result = pthread_mutex_init(&mu->lock_impl_, NULL);
Ian Rogersb033c752011-07-20 12:22:35 -070089 CHECK_EQ(0, result);
Carl Shapirob5573532011-07-12 18:22:59 -070090 return mu;
91}
92
93void Mutex::Lock() {
94 int result = pthread_mutex_lock(&lock_impl_);
95 CHECK_EQ(result, 0);
96 SetOwner(Thread::Current());
97}
98
99bool Mutex::TryLock() {
100 int result = pthread_mutex_lock(&lock_impl_);
101 if (result == EBUSY) {
102 return false;
103 } else {
104 CHECK_EQ(result, 0);
105 SetOwner(Thread::Current());
106 return true;
107 }
108}
109
110void Mutex::Unlock() {
111 CHECK(GetOwner() == Thread::Current());
112 int result = pthread_mutex_unlock(&lock_impl_);
113 CHECK_EQ(result, 0);
Elliott Hughesf4c21c92011-08-19 17:31:31 -0700114 SetOwner(NULL);
Carl Shapirob5573532011-07-12 18:22:59 -0700115}
116
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -0700117void Frame::Next() {
118 byte* next_sp = reinterpret_cast<byte*>(sp_) +
Shih-wei Liaod11af152011-08-23 16:02:11 -0700119 GetMethod()->GetFrameSizeInBytes();
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -0700120 sp_ = reinterpret_cast<const Method**>(next_sp);
121}
122
Shih-wei Liao55df06b2011-08-26 14:39:27 -0700123uintptr_t Frame::GetPC() const {
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -0700124 byte* pc_addr = reinterpret_cast<byte*>(sp_) +
Shih-wei Liaod11af152011-08-23 16:02:11 -0700125 GetMethod()->GetReturnPcOffsetInBytes();
Shih-wei Liao55df06b2011-08-26 14:39:27 -0700126 return *reinterpret_cast<uintptr_t*>(pc_addr);
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -0700127}
128
129const Method* Frame::NextMethod() const {
130 byte* next_sp = reinterpret_cast<byte*>(sp_) +
Shih-wei Liaod11af152011-08-23 16:02:11 -0700131 GetMethod()->GetFrameSizeInBytes();
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -0700132 return reinterpret_cast<const Method*>(next_sp);
133}
134
Carl Shapiro61e019d2011-07-14 16:53:09 -0700135void* ThreadStart(void *arg) {
Elliott Hughes53b61312011-08-12 18:28:20 -0700136 UNIMPLEMENTED(FATAL);
Carl Shapirob5573532011-07-12 18:22:59 -0700137 return NULL;
138}
139
Brian Carlstromb765be02011-08-17 23:54:10 -0700140Thread* Thread::Create(const Runtime* runtime) {
141 size_t stack_size = runtime->GetStackSize();
Carl Shapiro61e019d2011-07-14 16:53:09 -0700142
143 Thread* new_thread = new Thread;
Ian Rogers176f59c2011-07-20 13:14:11 -0700144 new_thread->InitCpu();
Carl Shapiro61e019d2011-07-14 16:53:09 -0700145
146 pthread_attr_t attr;
Elliott Hughese27955c2011-08-26 15:21:24 -0700147 errno = pthread_attr_init(&attr);
148 if (errno != 0) {
149 PLOG(FATAL) << "pthread_attr_init failed";
150 }
Carl Shapiro61e019d2011-07-14 16:53:09 -0700151
Elliott Hughese27955c2011-08-26 15:21:24 -0700152 errno = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
153 if (errno != 0) {
154 PLOG(FATAL) << "pthread_attr_setdetachstate(PTHREAD_CREATE_DETACHED) failed";
155 }
Carl Shapiro61e019d2011-07-14 16:53:09 -0700156
Elliott Hughese27955c2011-08-26 15:21:24 -0700157 errno = pthread_attr_setstacksize(&attr, stack_size);
158 if (errno != 0) {
159 PLOG(FATAL) << "pthread_attr_setstacksize(" << stack_size << ") failed";
160 }
Carl Shapiro61e019d2011-07-14 16:53:09 -0700161
Elliott Hughese27955c2011-08-26 15:21:24 -0700162 errno = pthread_create(&new_thread->handle_, &attr, ThreadStart, new_thread);
163 if (errno != 0) {
164 PLOG(FATAL) << "pthread_create failed";
165 }
166
167 errno = pthread_attr_destroy(&attr);
168 if (errno != 0) {
169 PLOG(FATAL) << "pthread_attr_destroy failed";
170 }
Carl Shapiro61e019d2011-07-14 16:53:09 -0700171
172 return new_thread;
173}
174
Elliott Hughes515a5bc2011-08-17 11:08:34 -0700175Thread* Thread::Attach(const Runtime* runtime) {
Carl Shapiro61e019d2011-07-14 16:53:09 -0700176 Thread* thread = new Thread;
Ian Rogers176f59c2011-07-20 13:14:11 -0700177 thread->InitCpu();
Carl Shapiro61e019d2011-07-14 16:53:09 -0700178
179 thread->handle_ = pthread_self();
180
181 thread->state_ = kRunnable;
182
Elliott Hughesa5780da2011-07-17 11:39:39 -0700183 errno = pthread_setspecific(Thread::pthread_key_self_, thread);
184 if (errno != 0) {
Elliott Hughesc1674ed2011-08-25 18:09:09 -0700185 PLOG(FATAL) << "pthread_setspecific failed";
Elliott Hughesa5780da2011-07-17 11:39:39 -0700186 }
187
Elliott Hughes75770752011-08-24 17:52:38 -0700188 thread->jni_env_ = new JNIEnvExt(thread, runtime->GetJavaVM());
Elliott Hughes330304d2011-08-12 14:28:05 -0700189
Carl Shapiro61e019d2011-07-14 16:53:09 -0700190 return thread;
191}
192
Elliott Hughese27955c2011-08-26 15:21:24 -0700193pid_t Thread::GetTid() const {
194 return gettid();
195}
196
Carl Shapirob5573532011-07-12 18:22:59 -0700197static void ThreadExitCheck(void* arg) {
198 LG << "Thread exit check";
199}
200
Elliott Hughesc1674ed2011-08-25 18:09:09 -0700201bool Thread::Startup() {
Carl Shapirob5573532011-07-12 18:22:59 -0700202 // Allocate a TLS slot.
Elliott Hughesc1674ed2011-08-25 18:09:09 -0700203 errno = pthread_key_create(&Thread::pthread_key_self_, ThreadExitCheck);
204 if (errno != 0) {
Elliott Hugheseb4f6142011-07-15 17:43:51 -0700205 PLOG(WARNING) << "pthread_key_create failed";
Carl Shapirob5573532011-07-12 18:22:59 -0700206 return false;
207 }
208
209 // Double-check the TLS slot allocation.
210 if (pthread_getspecific(pthread_key_self_) != NULL) {
Elliott Hugheseb4f6142011-07-15 17:43:51 -0700211 LOG(WARNING) << "newly-created pthread TLS slot is not NULL";
Carl Shapirob5573532011-07-12 18:22:59 -0700212 return false;
213 }
214
215 // TODO: initialize other locks and condition variables
216
217 return true;
218}
219
Elliott Hughesc1674ed2011-08-25 18:09:09 -0700220void Thread::Shutdown() {
221 errno = pthread_key_delete(Thread::pthread_key_self_);
222 if (errno != 0) {
223 PLOG(WARNING) << "pthread_key_delete failed";
224 }
225}
226
227Thread::~Thread() {
228 delete jni_env_;
229}
230
Ian Rogers408f79a2011-08-23 18:22:33 -0700231size_t Thread::NumSirtReferences() {
Ian Rogersa8cd9f42011-08-19 16:43:41 -0700232 size_t count = 0;
Ian Rogers408f79a2011-08-23 18:22:33 -0700233 for (StackIndirectReferenceTable* cur = top_sirt_; cur; cur = cur->Link()) {
Ian Rogersa8cd9f42011-08-19 16:43:41 -0700234 count += cur->NumberOfReferences();
235 }
236 return count;
237}
238
Ian Rogers408f79a2011-08-23 18:22:33 -0700239bool Thread::SirtContains(jobject obj) {
240 Object** sirt_entry = reinterpret_cast<Object**>(obj);
241 for (StackIndirectReferenceTable* cur = top_sirt_; cur; cur = cur->Link()) {
Ian Rogersa8cd9f42011-08-19 16:43:41 -0700242 size_t num_refs = cur->NumberOfReferences();
Ian Rogers408f79a2011-08-23 18:22:33 -0700243 // A SIRT should always have a jobject/jclass as a native method is passed
244 // in a this pointer or a class
245 DCHECK_GT(num_refs, 0u);
246 if ((&cur->References()[0] >= sirt_entry) &&
247 (sirt_entry <= (&cur->References()[num_refs-1]))) {
Ian Rogersa8cd9f42011-08-19 16:43:41 -0700248 return true;
249 }
250 }
251 return false;
252}
253
Ian Rogers408f79a2011-08-23 18:22:33 -0700254Object* Thread::DecodeJObject(jobject obj) {
255 // TODO: Only allowed to hold Object* when in the runnable state
256 // DCHECK(state_ == kRunnable);
257 if (obj == NULL) {
258 return NULL;
259 }
260 IndirectRef ref = reinterpret_cast<IndirectRef>(obj);
261 IndirectRefKind kind = GetIndirectRefKind(ref);
262 Object* result;
263 switch (kind) {
264 case kLocal:
265 {
Elliott Hughes69f5bc62011-08-24 09:26:14 -0700266 IndirectReferenceTable& locals = jni_env_->locals;
Ian Rogers408f79a2011-08-23 18:22:33 -0700267 result = locals.Get(ref);
268 break;
269 }
270 case kGlobal:
271 {
272 JavaVMExt* vm = Runtime::Current()->GetJavaVM();
273 IndirectReferenceTable& globals = vm->globals;
274 MutexLock mu(vm->globals_lock);
275 result = globals.Get(ref);
276 break;
277 }
278 case kWeakGlobal:
279 {
280 JavaVMExt* vm = Runtime::Current()->GetJavaVM();
281 IndirectReferenceTable& weak_globals = vm->weak_globals;
282 MutexLock mu(vm->weak_globals_lock);
283 result = weak_globals.Get(ref);
284 if (result == kClearedJniWeakGlobal) {
285 // This is a special case where it's okay to return NULL.
286 return NULL;
287 }
288 break;
289 }
290 case kSirtOrInvalid:
291 default:
292 // TODO: make stack indirect reference table lookup more efficient
293 // Check if this is a local reference in the SIRT
294 if (SirtContains(obj)) {
295 result = *reinterpret_cast<Object**>(obj); // Read from SIRT
296 } else if (false /*gDvmJni.workAroundAppJniBugs*/) { // TODO
297 // Assume an invalid local reference is actually a direct pointer.
298 result = reinterpret_cast<Object*>(obj);
299 } else {
300 LOG(FATAL) << "Invalid indirect reference " << obj;
301 result = reinterpret_cast<Object*>(kInvalidIndirectRefObject);
302 }
303 }
304
305 if (result == NULL) {
306 LOG(FATAL) << "JNI ERROR (app bug): use of deleted " << kind << ": "
307 << obj;
308 }
309 Heap::VerifyObject(result);
310 return result;
311}
312
Shih-wei Liao55df06b2011-08-26 14:39:27 -0700313// TODO: Replaces trace.method and trace.pc with IntArray nad
314// ObjectArray<Method>.
315Thread::InternalStackTrace* Thread::GetStackTrace(uint16_t length) {
316 Frame frame = Thread::Current()->GetTopOfStack();
317 InternalStackTrace *traces = new InternalStackTrace[length];
318 for (uint16_t i = 0; i < length && frame.HasNext(); ++i, frame.Next()) {
319 traces[i].method = frame.GetMethod();
320 traces[i].pc = frame.GetPC();
321 }
322 return traces;
323}
324
325ObjectArray<StackTraceElement>* Thread::GetStackTraceElement(uint16_t length, InternalStackTrace *raw_trace) {
326 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
327 ObjectArray<StackTraceElement>* java_traces = class_linker->AllocStackTraceElementArray(length);
328
329 for (uint16_t i = 0; i < length; ++i) {
330 // Prepare parameter for StackTraceElement(String cls, String method, String file, int line)
331 const Method* method = raw_trace[i].method;
332 const Class* klass = method->GetDeclaringClass();
333 const DexFile& dex_file = class_linker->FindDexFile(klass->GetDexCache());
334 String* readable_descriptor = String::AllocFromModifiedUtf8(PrettyDescriptor(klass->GetDescriptor()).c_str());
335
336 StackTraceElement* obj =
337 StackTraceElement::Alloc(readable_descriptor,
338 method->GetName(), String::AllocFromModifiedUtf8(klass->source_file_),
339 dex_file.GetLineNumFromPC(method, method->ToDexPC(raw_trace[i].pc)));
340 java_traces->Set(i, obj);
341 }
342 return java_traces;
343}
344
Elliott Hughese5b0dc82011-08-23 09:59:02 -0700345void Thread::ThrowNewException(const char* exception_class_descriptor, const char* fmt, ...) {
Elliott Hughes37f7a402011-08-22 18:56:01 -0700346 std::string msg;
Elliott Hughesa5b897e2011-08-16 11:33:06 -0700347 va_list args;
348 va_start(args, fmt);
Elliott Hughes37f7a402011-08-22 18:56:01 -0700349 StringAppendV(&msg, fmt, args);
Elliott Hughesa5b897e2011-08-16 11:33:06 -0700350 va_end(args);
Elliott Hughes37f7a402011-08-22 18:56:01 -0700351
Elliott Hughese5b0dc82011-08-23 09:59:02 -0700352 // Convert "Ljava/lang/Exception;" into JNI-style "java/lang/Exception".
353 CHECK(exception_class_descriptor[0] == 'L');
354 std::string descriptor(exception_class_descriptor + 1);
355 CHECK(descriptor[descriptor.length() - 1] == ';');
356 descriptor.erase(descriptor.length() - 1);
357
358 JNIEnv* env = GetJniEnv();
359 jclass exception_class = env->FindClass(descriptor.c_str());
360 CHECK(exception_class != NULL) << "descriptor=\"" << descriptor << "\"";
361 int rc = env->ThrowNew(exception_class, msg.c_str());
362 CHECK_EQ(rc, JNI_OK);
Elliott Hughesa5b897e2011-08-16 11:33:06 -0700363}
364
Elliott Hughes79082e32011-08-25 12:07:32 -0700365void Thread::ThrowOutOfMemoryError() {
366 UNIMPLEMENTED(FATAL);
367}
368
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -0700369Frame Thread::FindExceptionHandler(void* throw_pc, void** handler_pc) {
370 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
371 DCHECK(class_linker != NULL);
372
373 Frame cur_frame = GetTopOfStack();
374 for (int unwind_depth = 0; ; unwind_depth++) {
375 const Method* cur_method = cur_frame.GetMethod();
376 DexCache* dex_cache = cur_method->GetDeclaringClass()->GetDexCache();
377 const DexFile& dex_file = class_linker->FindDexFile(dex_cache);
378
379 void* handler_addr = FindExceptionHandlerInMethod(cur_method,
380 throw_pc,
381 dex_file,
382 class_linker);
383 if (handler_addr) {
384 *handler_pc = handler_addr;
385 return cur_frame;
386 } else {
387 // Check if we are at the last frame
388 if (cur_frame.HasNext()) {
389 cur_frame.Next();
390 } else {
391 // Either at the top of stack or next frame is native.
392 break;
393 }
394 }
395 }
396 *handler_pc = NULL;
397 return Frame();
398}
399
400void* Thread::FindExceptionHandlerInMethod(const Method* method,
401 void* throw_pc,
402 const DexFile& dex_file,
403 ClassLinker* class_linker) {
Elliott Hughese5b0dc82011-08-23 09:59:02 -0700404 Throwable* exception_obj = exception_;
Shih-wei Liao1a18c8c2011-08-14 17:47:36 -0700405 exception_ = NULL;
406
407 intptr_t dex_pc = -1;
408 const DexFile::CodeItem* code_item = dex_file.GetCodeItem(method->code_off_);
409 DexFile::CatchHandlerIterator iter;
410 for (iter = dex_file.dexFindCatchHandler(*code_item,
411 method->ToDexPC(reinterpret_cast<intptr_t>(throw_pc)));
412 !iter.HasNext();
413 iter.Next()) {
414 Class* klass = class_linker->FindSystemClass(dex_file.dexStringByTypeIdx(iter.Get().type_idx_));
415 DCHECK(klass != NULL);
416 if (exception_obj->InstanceOf(klass)) {
417 dex_pc = iter.Get().address_;
418 break;
419 }
420 }
421
422 exception_ = exception_obj;
423 if (iter.HasNext()) {
424 return NULL;
425 } else {
426 return reinterpret_cast<void*>( method->ToNativePC(dex_pc) );
427 }
428}
429
Ian Rogersb033c752011-07-20 12:22:35 -0700430static const char* kStateNames[] = {
431 "New",
432 "Runnable",
433 "Blocked",
434 "Waiting",
435 "TimedWaiting",
436 "Native",
437 "Terminated",
438};
439std::ostream& operator<<(std::ostream& os, const Thread::State& state) {
440 if (state >= Thread::kNew && state <= Thread::kTerminated) {
441 os << kStateNames[state-Thread::kNew];
442 } else {
443 os << "State[" << static_cast<int>(state) << "]";
444 }
445 return os;
446}
447
Elliott Hughes330304d2011-08-12 14:28:05 -0700448std::ostream& operator<<(std::ostream& os, const Thread& thread) {
449 os << "Thread[" << &thread
Elliott Hughese27955c2011-08-26 15:21:24 -0700450 << ",pthread_t=" << thread.GetImpl()
451 << ",tid=" << thread.GetTid()
452 << ",id=" << thread.GetId()
453 << ",state=" << thread.GetState() << "]";
Elliott Hughes330304d2011-08-12 14:28:05 -0700454 return os;
455}
456
Carl Shapiro61e019d2011-07-14 16:53:09 -0700457ThreadList* ThreadList::Create() {
458 return new ThreadList;
459}
460
Carl Shapirob5573532011-07-12 18:22:59 -0700461ThreadList::ThreadList() {
462 lock_ = Mutex::Create("ThreadList::Lock");
463}
464
465ThreadList::~ThreadList() {
Elliott Hughesc1674ed2011-08-25 18:09:09 -0700466 if (Contains(Thread::Current())) {
467 Runtime::Current()->DetachCurrentThread();
468 }
469
470 // All threads should have exited and unregistered when we
Carl Shapirob5573532011-07-12 18:22:59 -0700471 // reach this point. This means that all daemon threads had been
472 // shutdown cleanly.
Elliott Hughesc1674ed2011-08-25 18:09:09 -0700473 // TODO: dump ThreadList if non-empty.
474 CHECK_EQ(list_.size(), 0U);
475
Carl Shapirob5573532011-07-12 18:22:59 -0700476 delete lock_;
477 lock_ = NULL;
478}
479
Elliott Hughesc1674ed2011-08-25 18:09:09 -0700480bool ThreadList::Contains(Thread* thread) {
481 return find(list_.begin(), list_.end(), thread) != list_.end();
482}
483
Carl Shapirob5573532011-07-12 18:22:59 -0700484void ThreadList::Register(Thread* thread) {
485 MutexLock mu(lock_);
Elliott Hughesc1674ed2011-08-25 18:09:09 -0700486 CHECK(!Contains(thread));
Carl Shapirob5573532011-07-12 18:22:59 -0700487 list_.push_front(thread);
488}
489
490void ThreadList::Unregister(Thread* thread) {
491 MutexLock mu(lock_);
Elliott Hughesc1674ed2011-08-25 18:09:09 -0700492 CHECK(Contains(thread));
Carl Shapirob5573532011-07-12 18:22:59 -0700493 list_.remove(thread);
494}
495
Carl Shapirob5573532011-07-12 18:22:59 -0700496} // namespace