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); | |
157 Isolate::VisitIsolates(&pruner); | |
158 delete log_; | |
159 log_ = NULL; | |
160 RemoveThreadFromList(this); | |
161 } | 26 } |
162 | 27 |
163 | 28 |
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 } | |
186 | |
187 | |
188 void Thread::SetCurrent(Thread* current) { | |
189 OSThread::SetThreadLocal(thread_key_, reinterpret_cast<uword>(current)); | |
190 } | |
191 | |
192 | |
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) | 29 #if defined(DEBUG) |
204 #define REUSABLE_HANDLE_SCOPE_INIT(object) \ | 30 #define REUSABLE_HANDLE_SCOPE_INIT(object) \ |
205 reusable_##object##_handle_scope_active_(false), | 31 reusable_##object##_handle_scope_active_(false), |
206 #else | 32 #else |
207 #define REUSABLE_HANDLE_SCOPE_INIT(object) | 33 #define REUSABLE_HANDLE_SCOPE_INIT(object) |
208 #endif // defined(DEBUG) | 34 #endif // defined(DEBUG) |
209 | 35 |
210 #define REUSABLE_HANDLE_INITIALIZERS(object) \ | 36 #define REUSABLE_HANDLE_INITIALIZERS(object) \ |
211 object##_handle_(NULL), | 37 object##_handle_(NULL), |
212 | 38 |
213 | 39 |
214 Thread::Thread(bool init_vm_constants) | 40 Thread::Thread(Isolate* isolate) |
215 : id_(OSThread::GetCurrentThreadId()), | 41 : BaseThread(false), |
216 join_id_(OSThread::GetCurrentThreadJoinId()), | 42 os_thread_(NULL), |
217 trace_id_(OSThread::GetCurrentThreadTraceId()), | |
218 thread_interrupt_disabled_(1), // Thread interrupts disabled by default. | |
219 isolate_(NULL), | 43 isolate_(NULL), |
220 heap_(NULL), | 44 heap_(NULL), |
221 timeline_block_(NULL), | 45 zone_(NULL), |
| 46 top_exit_frame_info_(0), |
| 47 top_resource_(NULL), |
| 48 long_jump_base_(NULL), |
222 store_buffer_block_(NULL), | 49 store_buffer_block_(NULL), |
223 log_(new class Log()), | 50 no_callback_scope_depth_(0), |
224 REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_INITIALIZERS) | 51 #if defined(DEBUG) |
225 REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_SCOPE_INIT) | 52 top_handle_scope_(NULL), |
| 53 no_handle_scope_depth_(0), |
| 54 no_safepoint_scope_depth_(0), |
| 55 #endif |
226 reusable_handles_(), | 56 reusable_handles_(), |
227 cha_(NULL), | 57 cha_(NULL), |
228 deopt_id_(0), | 58 deopt_id_(0), |
229 vm_tag_(0), | 59 vm_tag_(0), |
230 pending_functions_(GrowableObjectArray::null()), | 60 pending_functions_(GrowableObjectArray::null()), |
231 no_callback_scope_depth_(0), | 61 REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_INITIALIZERS) |
232 thread_list_next_(NULL), | 62 REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_SCOPE_INIT) |
233 name_(NULL) { | 63 next_(NULL) { |
234 ClearState(); | |
235 | |
236 #define DEFAULT_INIT(type_name, member_name, init_expr, default_init_value) \ | 64 #define DEFAULT_INIT(type_name, member_name, init_expr, default_init_value) \ |
237 member_name = default_init_value; | 65 member_name = default_init_value; |
238 CACHED_CONSTANTS_LIST(DEFAULT_INIT) | 66 CACHED_CONSTANTS_LIST(DEFAULT_INIT) |
239 #undef DEFAULT_INIT | 67 #undef DEFAULT_INIT |
240 | 68 |
241 #define DEFAULT_INIT(name) \ | 69 #define DEFAULT_INIT(name) \ |
242 name##_entry_point_ = 0; | 70 name##_entry_point_ = 0; |
243 RUNTIME_ENTRY_LIST(DEFAULT_INIT) | 71 RUNTIME_ENTRY_LIST(DEFAULT_INIT) |
244 #undef DEFAULT_INIT | 72 #undef DEFAULT_INIT |
245 | 73 |
246 #define DEFAULT_INIT(returntype, name, ...) \ | 74 #define DEFAULT_INIT(returntype, name, ...) \ |
247 name##_entry_point_ = 0; | 75 name##_entry_point_ = 0; |
248 LEAF_RUNTIME_ENTRY_LIST(DEFAULT_INIT) | 76 LEAF_RUNTIME_ENTRY_LIST(DEFAULT_INIT) |
249 #undef DEFAULT_INIT | 77 #undef DEFAULT_INIT |
250 | 78 |
251 if (init_vm_constants) { | 79 // We cannot initialize the VM constants here for the vm isolate thread |
| 80 // due to boot strapping issues. |
| 81 if ((Dart::vm_isolate() != NULL) && (isolate != Dart::vm_isolate())) { |
252 InitVMConstants(); | 82 InitVMConstants(); |
253 } | 83 } |
254 SetCurrent(this); | |
255 AddThreadToList(this); | |
256 } | 84 } |
257 | 85 |
258 | 86 |
259 void Thread::InitVMConstants() { | 87 void Thread::InitVMConstants() { |
260 #define ASSERT_VM_HEAP(type_name, member_name, init_expr, default_init_value) \ | 88 #define ASSERT_VM_HEAP(type_name, member_name, init_expr, default_init_value) \ |
261 ASSERT((init_expr)->IsOldObject()); | 89 ASSERT((init_expr)->IsOldObject()); |
262 CACHED_VM_OBJECTS_LIST(ASSERT_VM_HEAP) | 90 CACHED_VM_OBJECTS_LIST(ASSERT_VM_HEAP) |
263 #undef ASSERT_VM_HEAP | 91 #undef ASSERT_VM_HEAP |
264 | 92 |
265 #define INIT_VALUE(type_name, member_name, init_expr, default_init_value) \ | 93 #define INIT_VALUE(type_name, member_name, init_expr, default_init_value) \ |
(...skipping 15 matching lines...) Expand all Loading... |
281 #undef INIT_VALUE | 109 #undef INIT_VALUE |
282 | 110 |
283 // Setup the thread specific reusable handles. | 111 // Setup the thread specific reusable handles. |
284 #define REUSABLE_HANDLE_ALLOCATION(object) \ | 112 #define REUSABLE_HANDLE_ALLOCATION(object) \ |
285 this->object##_handle_ = this->AllocateReusableHandle<object>(); | 113 this->object##_handle_ = this->AllocateReusableHandle<object>(); |
286 REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_ALLOCATION) | 114 REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_ALLOCATION) |
287 #undef REUSABLE_HANDLE_ALLOCATION | 115 #undef REUSABLE_HANDLE_ALLOCATION |
288 } | 116 } |
289 | 117 |
290 | 118 |
291 void Thread::ClearState() { | |
292 memset(&state_, 0, sizeof(state_)); | |
293 pending_functions_ = GrowableObjectArray::null(); | |
294 } | |
295 | |
296 | |
297 RawGrowableObjectArray* Thread::pending_functions() { | 119 RawGrowableObjectArray* Thread::pending_functions() { |
298 if (pending_functions_ == GrowableObjectArray::null()) { | 120 if (pending_functions_ == GrowableObjectArray::null()) { |
299 pending_functions_ = GrowableObjectArray::New(Heap::kOld); | 121 pending_functions_ = GrowableObjectArray::New(Heap::kOld); |
300 } | 122 } |
301 return pending_functions_; | 123 return pending_functions_; |
302 } | 124 } |
303 | 125 |
304 | 126 |
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) { | 127 void Thread::EnterIsolate(Isolate* isolate) { |
323 Thread* thread = Thread::Current(); | 128 const bool kIsMutatorThread = true; |
324 ASSERT(thread != NULL); | 129 const bool kDontBypassSafepoints = false; |
325 ASSERT(thread->isolate() == NULL); | 130 ThreadRegistry* tr = isolate->thread_registry(); |
326 ASSERT(!isolate->HasMutatorThread()); | 131 Thread* thread = tr->Schedule( |
327 thread->isolate_ = isolate; | 132 isolate, kIsMutatorThread, kDontBypassSafepoints); |
328 isolate->MakeCurrentThreadMutator(thread); | 133 isolate->MakeCurrentThreadMutator(thread); |
329 thread->set_vm_tag(VMTag::kVMTagId); | 134 thread->set_vm_tag(VMTag::kVMTagId); |
330 ASSERT(thread->store_buffer_block_ == NULL); | 135 ASSERT(thread->store_buffer_block_ == NULL); |
331 thread->StoreBufferAcquire(); | 136 thread->StoreBufferAcquire(); |
332 ASSERT(isolate->heap() != NULL); | |
333 thread->heap_ = isolate->heap(); | |
334 thread->Schedule(isolate); | |
335 thread->EnableThreadInterrupts(); | |
336 } | 137 } |
337 | 138 |
338 | 139 |
339 void Thread::ExitIsolate() { | 140 void Thread::ExitIsolate() { |
340 Thread* thread = Thread::Current(); | 141 Thread* thread = Thread::Current(); |
341 // TODO(koda): Audit callers; they should know whether they're in an isolate. | 142 ASSERT(thread != NULL); |
342 if (thread == NULL || thread->isolate() == NULL) return; | 143 ASSERT(thread->IsMutatorThread()); |
343 #if defined(DEBUG) | 144 #if defined(DEBUG) |
344 ASSERT(!thread->IsAnyReusableHandleScopeActive()); | 145 ASSERT(!thread->IsAnyReusableHandleScopeActive()); |
345 #endif // DEBUG | 146 #endif // DEBUG |
346 thread->DisableThreadInterrupts(); | |
347 // Clear since GC will not visit the thread once it is unscheduled. | 147 // Clear since GC will not visit the thread once it is unscheduled. |
348 thread->ClearReusableHandles(); | 148 thread->ClearReusableHandles(); |
| 149 thread->StoreBufferRelease(); |
349 Isolate* isolate = thread->isolate(); | 150 Isolate* isolate = thread->isolate(); |
350 thread->Unschedule(); | 151 ASSERT(isolate != NULL); |
351 // TODO(koda): Move store_buffer_block_ into State. | |
352 thread->StoreBufferRelease(); | |
353 if (isolate->is_runnable()) { | 152 if (isolate->is_runnable()) { |
354 thread->set_vm_tag(VMTag::kIdleTagId); | 153 thread->set_vm_tag(VMTag::kIdleTagId); |
355 } else { | 154 } else { |
356 thread->set_vm_tag(VMTag::kLoadWaitTagId); | 155 thread->set_vm_tag(VMTag::kLoadWaitTagId); |
357 } | 156 } |
| 157 const bool kIsMutatorThread = true; |
| 158 const bool kDontBypassSafepoints = false; |
| 159 ThreadRegistry* tr = isolate->thread_registry(); |
| 160 tr->Unschedule(thread, kIsMutatorThread, kDontBypassSafepoints); |
358 isolate->ClearMutatorThread(); | 161 isolate->ClearMutatorThread(); |
359 thread->isolate_ = NULL; | |
360 ASSERT(Isolate::Current() == NULL); | |
361 thread->heap_ = NULL; | |
362 } | 162 } |
363 | 163 |
364 | 164 |
365 void Thread::EnterIsolateAsHelper(Isolate* isolate, bool bypass_safepoint) { | 165 void Thread::EnterIsolateAsHelper(Isolate* isolate, bool bypass_safepoint) { |
366 Thread* thread = Thread::Current(); | 166 const bool kIsNotMutatorThread = false; |
367 ASSERT(thread != NULL); | 167 ThreadRegistry* tr = isolate->thread_registry(); |
368 ASSERT(thread->isolate() == NULL); | 168 Thread* thread = tr->Schedule(isolate, kIsNotMutatorThread, bypass_safepoint); |
369 thread->isolate_ = isolate; | |
370 ASSERT(thread->store_buffer_block_ == NULL); | 169 ASSERT(thread->store_buffer_block_ == NULL); |
371 // TODO(koda): Use StoreBufferAcquire once we properly flush before Scavenge. | 170 // TODO(koda): Use StoreBufferAcquire once we properly flush before Scavenge. |
372 thread->store_buffer_block_ = | 171 thread->store_buffer_block_ = |
373 thread->isolate()->store_buffer()->PopEmptyBlock(); | 172 thread->isolate()->store_buffer()->PopEmptyBlock(); |
374 ASSERT(isolate->heap() != NULL); | 173 // 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()); | 174 ASSERT(!thread->IsMutatorThread()); |
379 thread->Schedule(isolate, bypass_safepoint); | |
380 thread->EnableThreadInterrupts(); | |
381 } | 175 } |
382 | 176 |
383 | 177 |
384 void Thread::ExitIsolateAsHelper(bool bypass_safepoint) { | 178 void Thread::ExitIsolateAsHelper(bool bypass_safepoint) { |
385 Thread* thread = Thread::Current(); | 179 Thread* thread = Thread::Current(); |
386 thread->DisableThreadInterrupts(); | 180 ASSERT(thread != NULL); |
| 181 ASSERT(!thread->IsMutatorThread()); |
| 182 thread->StoreBufferRelease(); |
387 Isolate* isolate = thread->isolate(); | 183 Isolate* isolate = thread->isolate(); |
388 ASSERT(isolate != NULL); | 184 ASSERT(isolate != NULL); |
389 thread->Unschedule(bypass_safepoint); | 185 const bool kIsNotMutatorThread = false; |
390 // TODO(koda): Move store_buffer_block_ into State. | 186 ThreadRegistry* tr = isolate->thread_registry(); |
391 thread->StoreBufferRelease(); | 187 tr->Unschedule(thread, kIsNotMutatorThread, bypass_safepoint); |
392 thread->isolate_ = NULL; | |
393 thread->heap_ = NULL; | |
394 ASSERT(!thread->IsMutatorThread()); | |
395 } | 188 } |
396 | 189 |
397 | 190 |
398 // TODO(koda): Make non-static and invoke in SafepointThreads. | 191 // TODO(koda): Make non-static and invoke in SafepointThreads. |
399 void Thread::PrepareForGC() { | 192 void Thread::PrepareForGC() { |
400 Thread* thread = Thread::Current(); | 193 Thread* thread = Thread::Current(); |
401 // Prevent scheduling another GC. | 194 // Prevent scheduling another GC. |
402 thread->StoreBufferRelease(StoreBuffer::kIgnoreThreshold); | 195 thread->StoreBufferRelease(StoreBuffer::kIgnoreThreshold); |
403 // Make sure to get an *empty* block; the isolate needs all entries | 196 // Make sure to get an *empty* block; the isolate needs all entries |
404 // at GC time. | 197 // at GC time. |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
452 (vm_tag() == VMTag::kDartTagId); | 245 (vm_tag() == VMTag::kDartTagId); |
453 } | 246 } |
454 | 247 |
455 | 248 |
456 bool Thread::HasExitedDartCode() const { | 249 bool Thread::HasExitedDartCode() const { |
457 return (top_exit_frame_info() != 0) && | 250 return (top_exit_frame_info() != 0) && |
458 (vm_tag() != VMTag::kDartTagId); | 251 (vm_tag() != VMTag::kDartTagId); |
459 } | 252 } |
460 | 253 |
461 | 254 |
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> | 255 template<class C> |
480 C* Thread::AllocateReusableHandle() { | 256 C* Thread::AllocateReusableHandle() { |
481 C* handle = reinterpret_cast<C*>(reusable_handles_.AllocateScopedHandle()); | 257 C* handle = reinterpret_cast<C*>(reusable_handles_.AllocateScopedHandle()); |
482 C::initializeHandle(handle, C::null()); | 258 C::initializeHandle(handle, C::null()); |
483 return handle; | 259 return handle; |
484 } | 260 } |
485 | 261 |
486 | 262 |
487 void Thread::ClearReusableHandles() { | 263 void Thread::ClearReusableHandles() { |
488 #define CLEAR_REUSABLE_HANDLE(object) \ | 264 #define CLEAR_REUSABLE_HANDLE(object) \ |
489 *object##_handle_ = object::null(); | 265 *object##_handle_ = object::null(); |
490 REUSABLE_HANDLE_LIST(CLEAR_REUSABLE_HANDLE) | 266 REUSABLE_HANDLE_LIST(CLEAR_REUSABLE_HANDLE) |
491 #undef CLEAR_REUSABLE_HANDLE | 267 #undef CLEAR_REUSABLE_HANDLE |
492 } | 268 } |
493 | 269 |
494 | 270 |
495 void Thread::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 271 void Thread::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
496 ASSERT(visitor != NULL); | 272 ASSERT(visitor != NULL); |
497 | 273 |
498 // Visit objects in thread specific handles area. | 274 // Visit objects in thread specific handles area. |
499 reusable_handles_.VisitObjectPointers(visitor); | 275 reusable_handles_.VisitObjectPointers(visitor); |
500 | 276 |
501 if (pending_functions_ != GrowableObjectArray::null()) { | 277 if (pending_functions_ != GrowableObjectArray::null()) { |
502 visitor->VisitPointer( | 278 visitor->VisitPointer( |
503 reinterpret_cast<RawObject**>(&pending_functions_)); | 279 reinterpret_cast<RawObject**>(&pending_functions_)); |
504 } | 280 } |
505 } | 281 } |
506 | 282 |
507 | 283 |
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) { | 284 bool Thread::CanLoadFromThread(const Object& object) { |
537 #define CHECK_OBJECT(type_name, member_name, expr, default_init_value) \ | 285 #define CHECK_OBJECT(type_name, member_name, expr, default_init_value) \ |
538 if (object.raw() == expr) return true; | 286 if (object.raw() == expr) return true; |
539 CACHED_VM_OBJECTS_LIST(CHECK_OBJECT) | 287 CACHED_VM_OBJECTS_LIST(CHECK_OBJECT) |
540 #undef CHECK_OBJECT | 288 #undef CHECK_OBJECT |
541 return false; | 289 return false; |
542 } | 290 } |
543 | 291 |
544 | 292 |
545 intptr_t Thread::OffsetFromThread(const Object& object) { | 293 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(); \ | 326 return Thread::name##_entry_point_offset(); \ |
579 } | 327 } |
580 LEAF_RUNTIME_ENTRY_LIST(COMPUTE_OFFSET) | 328 LEAF_RUNTIME_ENTRY_LIST(COMPUTE_OFFSET) |
581 #undef COMPUTE_OFFSET | 329 #undef COMPUTE_OFFSET |
582 | 330 |
583 UNREACHABLE(); | 331 UNREACHABLE(); |
584 return -1; | 332 return -1; |
585 } | 333 } |
586 | 334 |
587 | 335 |
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) | 336 DisableThreadInterruptsScope::DisableThreadInterruptsScope(Thread* thread) |
620 : StackResource(thread) { | 337 : StackResource(thread) { |
621 if (thread != NULL) { | 338 if (thread != NULL) { |
622 thread->DisableThreadInterrupts(); | 339 OSThread* os_thread = thread->os_thread(); |
| 340 ASSERT(os_thread != NULL); |
| 341 os_thread->DisableThreadInterrupts(); |
623 } | 342 } |
624 } | 343 } |
625 | 344 |
626 | 345 |
627 DisableThreadInterruptsScope::~DisableThreadInterruptsScope() { | 346 DisableThreadInterruptsScope::~DisableThreadInterruptsScope() { |
628 if (thread() != NULL) { | 347 if (thread() != NULL) { |
629 thread()->EnableThreadInterrupts(); | 348 OSThread* os_thread = thread()->os_thread(); |
| 349 ASSERT(os_thread != NULL); |
| 350 os_thread->EnableThreadInterrupts(); |
630 } | 351 } |
631 } | 352 } |
632 | 353 |
633 } // namespace dart | 354 } // namespace dart |
OLD | NEW |