OLD | NEW |
---|---|
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/thread.h" | 5 #include "vm/thread.h" |
6 | 6 |
7 #include "vm/growable_array.h" | 7 #include "vm/growable_array.h" |
8 #include "vm/isolate.h" | 8 #include "vm/isolate.h" |
9 #include "vm/lockers.h" | 9 #include "vm/lockers.h" |
10 #include "vm/log.h" | 10 #include "vm/log.h" |
11 #include "vm/native_entry.h" | 11 #include "vm/native_entry.h" |
12 #include "vm/object.h" | 12 #include "vm/object.h" |
13 #include "vm/os_thread.h" | 13 #include "vm/os_thread.h" |
14 #include "vm/profiler.h" | 14 #include "vm/profiler.h" |
15 #include "vm/runtime_entry.h" | 15 #include "vm/runtime_entry.h" |
16 #include "vm/stub_code.h" | 16 #include "vm/stub_code.h" |
17 #include "vm/symbols.h" | 17 #include "vm/symbols.h" |
18 #include "vm/thread_interrupter.h" | 18 #include "vm/thread_interrupter.h" |
19 #include "vm/thread_registry.h" | 19 #include "vm/thread_registry.h" |
20 | 20 |
21 namespace dart { | 21 namespace dart { |
22 | 22 |
23 // The single thread local key which stores all the thread local data | |
24 // for a thread. | |
25 ThreadLocalKey Thread::thread_key_ = OSThread::kUnsetThreadLocalKey; | |
26 Thread* Thread::thread_list_head_ = NULL; | |
27 Mutex* Thread::thread_list_lock_ = NULL; | |
28 | |
29 // Remove |thread| from each isolate's thread registry. | |
30 class ThreadPruner : public IsolateVisitor { | |
31 public: | |
32 explicit ThreadPruner(Thread* thread) | |
33 : thread_(thread) { | |
34 ASSERT(thread_ != NULL); | |
35 } | |
36 | |
37 void VisitIsolate(Isolate* isolate) { | |
38 ThreadRegistry* registry = isolate->thread_registry(); | |
39 ASSERT(registry != NULL); | |
40 registry->PruneThread(thread_); | |
41 } | |
42 private: | |
43 Thread* thread_; | |
44 }; | |
45 | |
46 | |
47 void Thread::AddThreadToList(Thread* thread) { | |
48 ASSERT(thread != NULL); | |
49 ASSERT(thread->isolate() == NULL); | |
50 ASSERT(thread_list_lock_ != NULL); | |
51 MutexLocker ml(thread_list_lock_); | |
52 | |
53 ASSERT(thread->thread_list_next_ == NULL); | |
54 | |
55 #if defined(DEBUG) | |
56 { | |
57 // Ensure that we aren't already in the list. | |
58 Thread* current = thread_list_head_; | |
59 while (current != NULL) { | |
60 ASSERT(current != thread); | |
61 current = current->thread_list_next_; | |
62 } | |
63 } | |
64 #endif | |
65 | |
66 // Insert at head of list. | |
67 thread->thread_list_next_ = thread_list_head_; | |
68 thread_list_head_ = thread; | |
69 } | |
70 | |
71 | |
72 void Thread::RemoveThreadFromList(Thread* thread) { | |
73 ASSERT(thread != NULL); | |
74 ASSERT(thread->isolate() == NULL); | |
75 ASSERT(thread_list_lock_ != NULL); | |
76 MutexLocker ml(thread_list_lock_); | |
77 | |
78 // Handle case where |thread| is head of list. | |
79 if (thread_list_head_ == thread) { | |
80 thread_list_head_ = thread->thread_list_next_; | |
81 thread->thread_list_next_ = NULL; | |
82 return; | |
83 } | |
84 | |
85 Thread* current = thread_list_head_; | |
86 Thread* previous = NULL; | |
87 | |
88 // Scan across list and remove |thread|. | |
89 while (current != NULL) { | |
90 previous = current; | |
91 current = current->thread_list_next_; | |
92 if (current == thread) { | |
93 // We found |thread|, remove from list. | |
94 previous->thread_list_next_ = current->thread_list_next_; | |
95 thread->thread_list_next_ = NULL; | |
96 return; | |
97 } | |
98 } | |
99 | |
100 UNREACHABLE(); | |
101 } | |
102 | |
103 | |
104 bool Thread::IsThreadInList(ThreadId join_id) { | |
105 if (join_id == OSThread::kInvalidThreadJoinId) { | |
106 return false; | |
107 } | |
108 ThreadIterator it; | |
109 while (it.HasNext()) { | |
110 Thread* t = it.Next(); | |
111 // An address test is not sufficient because the allocator may recycle | |
112 // the address for another Thread. Test against the thread's join id. | |
113 if (t->join_id() == join_id) { | |
114 return true; | |
115 } | |
116 } | |
117 return false; | |
118 } | |
119 | |
120 | |
121 static void DeleteThread(void* thread) { | |
122 delete reinterpret_cast<Thread*>(thread); | |
123 } | |
124 | |
125 | |
126 void Thread::Shutdown() { | |
127 if (thread_list_lock_ != NULL) { | |
128 // Delete the current thread. | |
129 Thread* thread = Current(); | |
130 ASSERT(thread != NULL); | |
131 delete thread; | |
132 thread = NULL; | |
133 SetCurrent(NULL); | |
134 | |
135 // Check that there are no more threads, then delete the lock. | |
136 { | |
137 MutexLocker ml(thread_list_lock_); | |
138 ASSERT(thread_list_head_ == NULL); | |
139 } | |
140 | |
141 // Clean up TLS. | |
142 OSThread::DeleteThreadLocal(thread_key_); | |
143 thread_key_ = OSThread::kUnsetThreadLocalKey; | |
144 | |
145 // Delete the thread list lock. | |
146 delete thread_list_lock_; | |
147 thread_list_lock_ = NULL; | |
148 } | |
149 } | |
150 | |
151 | |
152 Thread::~Thread() { | 23 Thread::~Thread() { |
153 // We should cleanly exit any isolate before destruction. | 24 // We should cleanly exit any isolate before destruction. |
154 ASSERT(isolate_ == NULL); | 25 ASSERT(isolate_ == NULL); |
155 // Clear |this| from all isolate's thread registry. | |
156 ThreadPruner pruner(this); | |
zra
2015/11/16 20:12:28
What prunes threads from the registry now?
siva
2015/11/17 20:52:25
The thread registry destructor deletes any remaini
| |
157 Isolate::VisitIsolates(&pruner); | |
158 delete log_; | |
159 log_ = NULL; | |
160 RemoveThreadFromList(this); | |
161 } | |
162 | |
163 | |
164 void Thread::InitOnceBeforeIsolate() { | |
165 ASSERT(thread_list_lock_ == NULL); | |
166 thread_list_lock_ = new Mutex(); | |
167 ASSERT(thread_list_lock_ != NULL); | |
168 ASSERT(thread_key_ == OSThread::kUnsetThreadLocalKey); | |
169 thread_key_ = OSThread::CreateThreadLocal(DeleteThread); | |
170 ASSERT(thread_key_ != OSThread::kUnsetThreadLocalKey); | |
171 ASSERT(Thread::Current() == NULL); | |
172 // Allocate a new Thread and postpone initialization of VM constants for | |
173 // this first thread. | |
174 Thread* thread = new Thread(false); | |
175 // Verify that current thread was set. | |
176 ASSERT(Thread::Current() == thread); | |
177 } | |
178 | |
179 | |
180 void Thread::InitOnceAfterObjectAndStubCode() { | |
181 Thread* thread = Thread::Current(); | |
182 ASSERT(thread != NULL); | |
183 ASSERT(thread->isolate() == Dart::vm_isolate()); | |
184 thread->InitVMConstants(); | |
185 } | 26 } |
186 | 27 |
187 | 28 |
188 void Thread::SetCurrent(Thread* current) { | 29 void Thread::SetCurrent(Thread* current) { |
189 OSThread::SetThreadLocal(thread_key_, reinterpret_cast<uword>(current)); | 30 OSThread::SetThreadLocal(OSThread::thread_key_, |
31 reinterpret_cast<uword>(current)); | |
190 } | 32 } |
191 | 33 |
192 | 34 |
193 void Thread::EnsureInit() { | |
194 if (Thread::Current() == NULL) { | |
195 // Allocate a new Thread. | |
196 Thread* thread = new Thread(); | |
197 // Verify that current thread was set. | |
198 ASSERT(Thread::Current() == thread); | |
199 } | |
200 } | |
201 | |
202 | |
203 #if defined(DEBUG) | 35 #if defined(DEBUG) |
204 #define REUSABLE_HANDLE_SCOPE_INIT(object) \ | 36 #define REUSABLE_HANDLE_SCOPE_INIT(object) \ |
205 reusable_##object##_handle_scope_active_(false), | 37 reusable_##object##_handle_scope_active_(false), |
206 #else | 38 #else |
207 #define REUSABLE_HANDLE_SCOPE_INIT(object) | 39 #define REUSABLE_HANDLE_SCOPE_INIT(object) |
208 #endif // defined(DEBUG) | 40 #endif // defined(DEBUG) |
209 | 41 |
210 #define REUSABLE_HANDLE_INITIALIZERS(object) \ | 42 #define REUSABLE_HANDLE_INITIALIZERS(object) \ |
211 object##_handle_(NULL), | 43 object##_handle_(NULL), |
212 | 44 |
213 | 45 |
214 Thread::Thread(bool init_vm_constants) | 46 Thread::Thread(Isolate* isolate) |
215 : id_(OSThread::GetCurrentThreadId()), | 47 : BaseThread(false), |
216 join_id_(OSThread::GetCurrentThreadJoinId()), | 48 os_thread_(NULL), |
217 trace_id_(OSThread::GetCurrentThreadTraceId()), | |
218 thread_interrupt_disabled_(1), // Thread interrupts disabled by default. | |
219 isolate_(NULL), | 49 isolate_(NULL), |
220 heap_(NULL), | 50 heap_(NULL), |
221 timeline_block_(NULL), | 51 zone_(NULL), |
52 top_exit_frame_info_(0), | |
53 top_resource_(NULL), | |
54 long_jump_base_(NULL), | |
222 store_buffer_block_(NULL), | 55 store_buffer_block_(NULL), |
223 log_(new class Log()), | 56 no_callback_scope_depth_(0), |
224 REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_INITIALIZERS) | 57 #if defined(DEBUG) |
225 REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_SCOPE_INIT) | 58 top_handle_scope_(NULL), |
59 no_handle_scope_depth_(0), | |
60 no_safepoint_scope_depth_(0), | |
61 #endif | |
226 reusable_handles_(), | 62 reusable_handles_(), |
227 cha_(NULL), | 63 cha_(NULL), |
228 deopt_id_(0), | 64 deopt_id_(0), |
229 vm_tag_(0), | 65 vm_tag_(0), |
230 pending_functions_(GrowableObjectArray::null()), | 66 pending_functions_(GrowableObjectArray::null()), |
231 no_callback_scope_depth_(0), | 67 REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_INITIALIZERS) |
232 thread_list_next_(NULL), | 68 REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_SCOPE_INIT) |
233 name_(NULL) { | 69 next_(NULL) { |
234 ClearState(); | |
235 | |
236 #define DEFAULT_INIT(type_name, member_name, init_expr, default_init_value) \ | 70 #define DEFAULT_INIT(type_name, member_name, init_expr, default_init_value) \ |
237 member_name = default_init_value; | 71 member_name = default_init_value; |
238 CACHED_CONSTANTS_LIST(DEFAULT_INIT) | 72 CACHED_CONSTANTS_LIST(DEFAULT_INIT) |
239 #undef DEFAULT_INIT | 73 #undef DEFAULT_INIT |
240 | 74 |
241 #define DEFAULT_INIT(name) \ | 75 #define DEFAULT_INIT(name) \ |
242 name##_entry_point_ = 0; | 76 name##_entry_point_ = 0; |
243 RUNTIME_ENTRY_LIST(DEFAULT_INIT) | 77 RUNTIME_ENTRY_LIST(DEFAULT_INIT) |
244 #undef DEFAULT_INIT | 78 #undef DEFAULT_INIT |
245 | 79 |
246 #define DEFAULT_INIT(returntype, name, ...) \ | 80 #define DEFAULT_INIT(returntype, name, ...) \ |
247 name##_entry_point_ = 0; | 81 name##_entry_point_ = 0; |
248 LEAF_RUNTIME_ENTRY_LIST(DEFAULT_INIT) | 82 LEAF_RUNTIME_ENTRY_LIST(DEFAULT_INIT) |
249 #undef DEFAULT_INIT | 83 #undef DEFAULT_INIT |
250 | 84 |
251 if (init_vm_constants) { | 85 // We cannot initialize the VM constants here for the vm isolate thread |
86 // due to boot strapping issues. | |
87 if ((Dart::vm_isolate() != NULL) && (isolate != Dart::vm_isolate())) { | |
252 InitVMConstants(); | 88 InitVMConstants(); |
253 } | 89 } |
254 SetCurrent(this); | |
255 AddThreadToList(this); | |
256 } | 90 } |
257 | 91 |
258 | 92 |
259 void Thread::InitVMConstants() { | 93 void Thread::InitVMConstants() { |
260 #define ASSERT_VM_HEAP(type_name, member_name, init_expr, default_init_value) \ | 94 #define ASSERT_VM_HEAP(type_name, member_name, init_expr, default_init_value) \ |
261 ASSERT((init_expr)->IsOldObject()); | 95 ASSERT((init_expr)->IsOldObject()); |
262 CACHED_VM_OBJECTS_LIST(ASSERT_VM_HEAP) | 96 CACHED_VM_OBJECTS_LIST(ASSERT_VM_HEAP) |
263 #undef ASSERT_VM_HEAP | 97 #undef ASSERT_VM_HEAP |
264 | 98 |
265 #define INIT_VALUE(type_name, member_name, init_expr, default_init_value) \ | 99 #define INIT_VALUE(type_name, member_name, init_expr, default_init_value) \ |
(...skipping 15 matching lines...) Expand all Loading... | |
281 #undef INIT_VALUE | 115 #undef INIT_VALUE |
282 | 116 |
283 // Setup the thread specific reusable handles. | 117 // Setup the thread specific reusable handles. |
284 #define REUSABLE_HANDLE_ALLOCATION(object) \ | 118 #define REUSABLE_HANDLE_ALLOCATION(object) \ |
285 this->object##_handle_ = this->AllocateReusableHandle<object>(); | 119 this->object##_handle_ = this->AllocateReusableHandle<object>(); |
286 REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_ALLOCATION) | 120 REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_ALLOCATION) |
287 #undef REUSABLE_HANDLE_ALLOCATION | 121 #undef REUSABLE_HANDLE_ALLOCATION |
288 } | 122 } |
289 | 123 |
290 | 124 |
291 void Thread::ClearState() { | |
292 memset(&state_, 0, sizeof(state_)); | |
293 pending_functions_ = GrowableObjectArray::null(); | |
294 } | |
295 | |
296 | |
297 RawGrowableObjectArray* Thread::pending_functions() { | 125 RawGrowableObjectArray* Thread::pending_functions() { |
298 if (pending_functions_ == GrowableObjectArray::null()) { | 126 if (pending_functions_ == GrowableObjectArray::null()) { |
299 pending_functions_ = GrowableObjectArray::New(Heap::kOld); | 127 pending_functions_ = GrowableObjectArray::New(Heap::kOld); |
300 } | 128 } |
301 return pending_functions_; | 129 return pending_functions_; |
302 } | 130 } |
303 | 131 |
304 | 132 |
305 void Thread::Schedule(Isolate* isolate, bool bypass_safepoint) { | |
306 State st; | |
307 if (isolate->thread_registry()->RestoreStateTo(this, &st, bypass_safepoint)) { | |
308 ASSERT(isolate->thread_registry()->Contains(this)); | |
309 state_ = st; | |
310 } | |
311 } | |
312 | |
313 | |
314 void Thread::Unschedule(bool bypass_safepoint) { | |
315 ThreadRegistry* reg = isolate_->thread_registry(); | |
316 ASSERT(reg->Contains(this)); | |
317 reg->SaveStateFrom(this, state_, bypass_safepoint); | |
318 ClearState(); | |
319 } | |
320 | |
321 | |
322 void Thread::EnterIsolate(Isolate* isolate) { | 133 void Thread::EnterIsolate(Isolate* isolate) { |
323 Thread* thread = Thread::Current(); | 134 const bool kIsMutatorThread = true; |
324 ASSERT(thread != NULL); | 135 const bool kDontBypassSafepoints = false; |
325 ASSERT(thread->isolate() == NULL); | 136 ThreadRegistry* tr = isolate->thread_registry(); |
326 ASSERT(!isolate->HasMutatorThread()); | 137 Thread* thread = tr->Schedule( |
327 thread->isolate_ = isolate; | 138 isolate, kIsMutatorThread, kDontBypassSafepoints); |
328 isolate->MakeCurrentThreadMutator(thread); | 139 isolate->MakeCurrentThreadMutator(thread); |
329 thread->set_vm_tag(VMTag::kVMTagId); | 140 thread->set_vm_tag(VMTag::kVMTagId); |
330 ASSERT(thread->store_buffer_block_ == NULL); | 141 ASSERT(thread->store_buffer_block_ == NULL); |
331 thread->StoreBufferAcquire(); | 142 thread->StoreBufferAcquire(); |
332 ASSERT(isolate->heap() != NULL); | |
333 thread->heap_ = isolate->heap(); | |
334 thread->Schedule(isolate); | |
335 thread->EnableThreadInterrupts(); | |
336 } | 143 } |
337 | 144 |
338 | 145 |
339 void Thread::ExitIsolate() { | 146 void Thread::ExitIsolate() { |
340 Thread* thread = Thread::Current(); | 147 Thread* thread = Thread::Current(); |
341 // TODO(koda): Audit callers; they should know whether they're in an isolate. | 148 ASSERT(thread != NULL); |
342 if (thread == NULL || thread->isolate() == NULL) return; | 149 ASSERT(thread->IsMutatorThread()); |
343 #if defined(DEBUG) | 150 #if defined(DEBUG) |
344 ASSERT(!thread->IsAnyReusableHandleScopeActive()); | 151 ASSERT(!thread->IsAnyReusableHandleScopeActive()); |
345 #endif // DEBUG | 152 #endif // DEBUG |
346 thread->DisableThreadInterrupts(); | |
347 // Clear since GC will not visit the thread once it is unscheduled. | 153 // Clear since GC will not visit the thread once it is unscheduled. |
348 thread->ClearReusableHandles(); | 154 thread->ClearReusableHandles(); |
155 thread->StoreBufferRelease(); | |
349 Isolate* isolate = thread->isolate(); | 156 Isolate* isolate = thread->isolate(); |
350 thread->Unschedule(); | 157 ASSERT(isolate != NULL); |
351 // TODO(koda): Move store_buffer_block_ into State. | |
352 thread->StoreBufferRelease(); | |
353 if (isolate->is_runnable()) { | 158 if (isolate->is_runnable()) { |
354 thread->set_vm_tag(VMTag::kIdleTagId); | 159 thread->set_vm_tag(VMTag::kIdleTagId); |
355 } else { | 160 } else { |
356 thread->set_vm_tag(VMTag::kLoadWaitTagId); | 161 thread->set_vm_tag(VMTag::kLoadWaitTagId); |
357 } | 162 } |
163 const bool kIsMutatorThread = true; | |
164 const bool kDontBypassSafepoints = false; | |
165 ThreadRegistry* tr = isolate->thread_registry(); | |
166 tr->Unschedule(thread, kIsMutatorThread, kDontBypassSafepoints); | |
358 isolate->ClearMutatorThread(); | 167 isolate->ClearMutatorThread(); |
359 thread->isolate_ = NULL; | |
360 ASSERT(Isolate::Current() == NULL); | |
361 thread->heap_ = NULL; | |
362 } | 168 } |
363 | 169 |
364 | 170 |
365 void Thread::EnterIsolateAsHelper(Isolate* isolate, bool bypass_safepoint) { | 171 void Thread::EnterIsolateAsHelper(Isolate* isolate, bool bypass_safepoint) { |
366 Thread* thread = Thread::Current(); | 172 const bool kIsNotMutatorThread = false; |
367 ASSERT(thread != NULL); | 173 ThreadRegistry* tr = isolate->thread_registry(); |
368 ASSERT(thread->isolate() == NULL); | 174 Thread* thread = tr->Schedule(isolate, kIsNotMutatorThread, bypass_safepoint); |
369 thread->isolate_ = isolate; | |
370 ASSERT(thread->store_buffer_block_ == NULL); | 175 ASSERT(thread->store_buffer_block_ == NULL); |
371 // TODO(koda): Use StoreBufferAcquire once we properly flush before Scavenge. | 176 // TODO(koda): Use StoreBufferAcquire once we properly flush before Scavenge. |
372 thread->store_buffer_block_ = | 177 thread->store_buffer_block_ = |
373 thread->isolate()->store_buffer()->PopEmptyBlock(); | 178 thread->isolate()->store_buffer()->PopEmptyBlock(); |
374 ASSERT(isolate->heap() != NULL); | 179 // This thread should not be the main mutator. |
375 thread->heap_ = isolate->heap(); | |
376 // Do not update isolate->mutator_thread, but perform sanity check: | |
377 // this thread should not be both the main mutator and helper. | |
378 ASSERT(!thread->IsMutatorThread()); | 180 ASSERT(!thread->IsMutatorThread()); |
379 thread->Schedule(isolate, bypass_safepoint); | |
380 thread->EnableThreadInterrupts(); | |
381 } | 181 } |
382 | 182 |
383 | 183 |
384 void Thread::ExitIsolateAsHelper(bool bypass_safepoint) { | 184 void Thread::ExitIsolateAsHelper(bool bypass_safepoint) { |
385 Thread* thread = Thread::Current(); | 185 Thread* thread = Thread::Current(); |
386 thread->DisableThreadInterrupts(); | 186 ASSERT(thread != NULL); |
187 ASSERT(!thread->IsMutatorThread()); | |
188 thread->StoreBufferRelease(); | |
387 Isolate* isolate = thread->isolate(); | 189 Isolate* isolate = thread->isolate(); |
388 ASSERT(isolate != NULL); | 190 ASSERT(isolate != NULL); |
389 thread->Unschedule(bypass_safepoint); | 191 const bool kIsNotMutatorThread = false; |
390 // TODO(koda): Move store_buffer_block_ into State. | 192 ThreadRegistry* tr = isolate->thread_registry(); |
391 thread->StoreBufferRelease(); | 193 tr->Unschedule(thread, kIsNotMutatorThread, bypass_safepoint); |
392 thread->isolate_ = NULL; | |
393 thread->heap_ = NULL; | |
394 ASSERT(!thread->IsMutatorThread()); | |
395 } | 194 } |
396 | 195 |
397 | 196 |
398 // TODO(koda): Make non-static and invoke in SafepointThreads. | 197 // TODO(koda): Make non-static and invoke in SafepointThreads. |
399 void Thread::PrepareForGC() { | 198 void Thread::PrepareForGC() { |
400 Thread* thread = Thread::Current(); | 199 Thread* thread = Thread::Current(); |
401 // Prevent scheduling another GC. | 200 // Prevent scheduling another GC. |
402 thread->StoreBufferRelease(StoreBuffer::kIgnoreThreshold); | 201 thread->StoreBufferRelease(StoreBuffer::kIgnoreThreshold); |
403 // Make sure to get an *empty* block; the isolate needs all entries | 202 // Make sure to get an *empty* block; the isolate needs all entries |
404 // at GC time. | 203 // at GC time. |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
452 (vm_tag() == VMTag::kDartTagId); | 251 (vm_tag() == VMTag::kDartTagId); |
453 } | 252 } |
454 | 253 |
455 | 254 |
456 bool Thread::HasExitedDartCode() const { | 255 bool Thread::HasExitedDartCode() const { |
457 return (top_exit_frame_info() != 0) && | 256 return (top_exit_frame_info() != 0) && |
458 (vm_tag() != VMTag::kDartTagId); | 257 (vm_tag() != VMTag::kDartTagId); |
459 } | 258 } |
460 | 259 |
461 | 260 |
462 CHA* Thread::cha() const { | |
463 ASSERT(isolate_ != NULL); | |
464 return cha_; | |
465 } | |
466 | |
467 | |
468 void Thread::set_cha(CHA* value) { | |
469 ASSERT(isolate_ != NULL); | |
470 cha_ = value; | |
471 } | |
472 | |
473 | |
474 Log* Thread::log() const { | |
475 return log_; | |
476 } | |
477 | |
478 | |
479 template<class C> | 261 template<class C> |
480 C* Thread::AllocateReusableHandle() { | 262 C* Thread::AllocateReusableHandle() { |
481 C* handle = reinterpret_cast<C*>(reusable_handles_.AllocateScopedHandle()); | 263 C* handle = reinterpret_cast<C*>(reusable_handles_.AllocateScopedHandle()); |
482 C::initializeHandle(handle, C::null()); | 264 C::initializeHandle(handle, C::null()); |
483 return handle; | 265 return handle; |
484 } | 266 } |
485 | 267 |
486 | 268 |
487 void Thread::ClearReusableHandles() { | 269 void Thread::ClearReusableHandles() { |
488 #define CLEAR_REUSABLE_HANDLE(object) \ | 270 #define CLEAR_REUSABLE_HANDLE(object) \ |
489 *object##_handle_ = object::null(); | 271 *object##_handle_ = object::null(); |
490 REUSABLE_HANDLE_LIST(CLEAR_REUSABLE_HANDLE) | 272 REUSABLE_HANDLE_LIST(CLEAR_REUSABLE_HANDLE) |
491 #undef CLEAR_REUSABLE_HANDLE | 273 #undef CLEAR_REUSABLE_HANDLE |
492 } | 274 } |
493 | 275 |
494 | 276 |
495 void Thread::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 277 void Thread::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
496 ASSERT(visitor != NULL); | 278 ASSERT(visitor != NULL); |
497 | 279 |
498 // Visit objects in thread specific handles area. | 280 // Visit objects in thread specific handles area. |
499 reusable_handles_.VisitObjectPointers(visitor); | 281 reusable_handles_.VisitObjectPointers(visitor); |
500 | 282 |
501 if (pending_functions_ != GrowableObjectArray::null()) { | 283 if (pending_functions_ != GrowableObjectArray::null()) { |
502 visitor->VisitPointer( | 284 visitor->VisitPointer( |
503 reinterpret_cast<RawObject**>(&pending_functions_)); | 285 reinterpret_cast<RawObject**>(&pending_functions_)); |
504 } | 286 } |
505 } | 287 } |
506 | 288 |
507 | 289 |
508 void Thread::DisableThreadInterrupts() { | |
509 ASSERT(Thread::Current() == this); | |
510 AtomicOperations::FetchAndIncrement(&thread_interrupt_disabled_); | |
511 } | |
512 | |
513 | |
514 void Thread::EnableThreadInterrupts() { | |
515 ASSERT(Thread::Current() == this); | |
516 uintptr_t old = | |
517 AtomicOperations::FetchAndDecrement(&thread_interrupt_disabled_); | |
518 if (old == 1) { | |
519 // We just decremented from 1 to 0. | |
520 // Make sure the thread interrupter is awake. | |
521 ThreadInterrupter::WakeUp(); | |
522 } | |
523 if (old == 0) { | |
524 // We just decremented from 0, this means we've got a mismatched pair | |
525 // of calls to EnableThreadInterrupts and DisableThreadInterrupts. | |
526 FATAL("Invalid call to Thread::EnableThreadInterrupts()"); | |
527 } | |
528 } | |
529 | |
530 | |
531 bool Thread::ThreadInterruptsEnabled() { | |
532 return AtomicOperations::LoadRelaxed(&thread_interrupt_disabled_) == 0; | |
533 } | |
534 | |
535 | |
536 bool Thread::CanLoadFromThread(const Object& object) { | 290 bool Thread::CanLoadFromThread(const Object& object) { |
537 #define CHECK_OBJECT(type_name, member_name, expr, default_init_value) \ | 291 #define CHECK_OBJECT(type_name, member_name, expr, default_init_value) \ |
538 if (object.raw() == expr) return true; | 292 if (object.raw() == expr) return true; |
539 CACHED_VM_OBJECTS_LIST(CHECK_OBJECT) | 293 CACHED_VM_OBJECTS_LIST(CHECK_OBJECT) |
540 #undef CHECK_OBJECT | 294 #undef CHECK_OBJECT |
541 return false; | 295 return false; |
542 } | 296 } |
543 | 297 |
544 | 298 |
545 intptr_t Thread::OffsetFromThread(const Object& object) { | 299 intptr_t Thread::OffsetFromThread(const Object& object) { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
578 return Thread::name##_entry_point_offset(); \ | 332 return Thread::name##_entry_point_offset(); \ |
579 } | 333 } |
580 LEAF_RUNTIME_ENTRY_LIST(COMPUTE_OFFSET) | 334 LEAF_RUNTIME_ENTRY_LIST(COMPUTE_OFFSET) |
581 #undef COMPUTE_OFFSET | 335 #undef COMPUTE_OFFSET |
582 | 336 |
583 UNREACHABLE(); | 337 UNREACHABLE(); |
584 return -1; | 338 return -1; |
585 } | 339 } |
586 | 340 |
587 | 341 |
588 ThreadIterator::ThreadIterator() { | |
589 ASSERT(Thread::thread_list_lock_ != NULL); | |
590 // Lock the thread list while iterating. | |
591 Thread::thread_list_lock_->Lock(); | |
592 next_ = Thread::thread_list_head_; | |
593 } | |
594 | |
595 | |
596 ThreadIterator::~ThreadIterator() { | |
597 ASSERT(Thread::thread_list_lock_ != NULL); | |
598 // Unlock the thread list when done. | |
599 Thread::thread_list_lock_->Unlock(); | |
600 } | |
601 | |
602 | |
603 bool ThreadIterator::HasNext() const { | |
604 ASSERT(Thread::thread_list_lock_ != NULL); | |
605 ASSERT(Thread::thread_list_lock_->IsOwnedByCurrentThread()); | |
606 return next_ != NULL; | |
607 } | |
608 | |
609 | |
610 Thread* ThreadIterator::Next() { | |
611 ASSERT(Thread::thread_list_lock_ != NULL); | |
612 ASSERT(Thread::thread_list_lock_->IsOwnedByCurrentThread()); | |
613 Thread* current = next_; | |
614 next_ = next_->thread_list_next_; | |
615 return current; | |
616 } | |
617 | |
618 | |
619 DisableThreadInterruptsScope::DisableThreadInterruptsScope(Thread* thread) | 342 DisableThreadInterruptsScope::DisableThreadInterruptsScope(Thread* thread) |
620 : StackResource(thread) { | 343 : StackResource(thread) { |
621 if (thread != NULL) { | 344 if (thread != NULL) { |
622 thread->DisableThreadInterrupts(); | 345 OSThread* os_thread = thread->os_thread(); |
346 ASSERT(os_thread != NULL); | |
347 os_thread->DisableThreadInterrupts(); | |
623 } | 348 } |
624 } | 349 } |
625 | 350 |
626 | 351 |
627 DisableThreadInterruptsScope::~DisableThreadInterruptsScope() { | 352 DisableThreadInterruptsScope::~DisableThreadInterruptsScope() { |
628 if (thread() != NULL) { | 353 if (thread() != NULL) { |
629 thread()->EnableThreadInterrupts(); | 354 OSThread* os_thread = thread()->os_thread(); |
355 ASSERT(os_thread != NULL); | |
356 os_thread->EnableThreadInterrupts(); | |
630 } | 357 } |
631 } | 358 } |
632 | 359 |
633 } // namespace dart | 360 } // namespace dart |
OLD | NEW |