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" |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
189 #define REUSABLE_HANDLE_SCOPE_INIT(object) | 189 #define REUSABLE_HANDLE_SCOPE_INIT(object) |
190 #endif // defined(DEBUG) | 190 #endif // defined(DEBUG) |
191 | 191 |
192 #define REUSABLE_HANDLE_INITIALIZERS(object) \ | 192 #define REUSABLE_HANDLE_INITIALIZERS(object) \ |
193 object##_handle_(NULL), | 193 object##_handle_(NULL), |
194 | 194 |
195 | 195 |
196 Thread::Thread(bool init_vm_constants) | 196 Thread::Thread(bool init_vm_constants) |
197 : id_(OSThread::GetCurrentThreadId()), | 197 : id_(OSThread::GetCurrentThreadId()), |
198 join_id_(OSThread::GetCurrentThreadJoinId()), | 198 join_id_(OSThread::GetCurrentThreadJoinId()), |
199 thread_interrupt_callback_(NULL), | 199 thread_interrupt_disabled_(1), // Thread interrupts disabled by default. |
200 thread_interrupt_data_(NULL), | |
201 isolate_(NULL), | 200 isolate_(NULL), |
202 heap_(NULL), | 201 heap_(NULL), |
203 timeline_block_(NULL), | 202 timeline_block_(NULL), |
204 store_buffer_block_(NULL), | 203 store_buffer_block_(NULL), |
205 log_(new class Log()), | 204 log_(new class Log()), |
206 REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_INITIALIZERS) | 205 REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_INITIALIZERS) |
207 REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_SCOPE_INIT) | 206 REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_SCOPE_INIT) |
208 reusable_handles_(), | 207 reusable_handles_(), |
209 cha_(NULL), | 208 cha_(NULL), |
210 deopt_id_(0), | 209 deopt_id_(0), |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
306 ASSERT(thread->isolate() == NULL); | 305 ASSERT(thread->isolate() == NULL); |
307 ASSERT(!isolate->HasMutatorThread()); | 306 ASSERT(!isolate->HasMutatorThread()); |
308 thread->isolate_ = isolate; | 307 thread->isolate_ = isolate; |
309 isolate->MakeCurrentThreadMutator(thread); | 308 isolate->MakeCurrentThreadMutator(thread); |
310 thread->set_vm_tag(VMTag::kVMTagId); | 309 thread->set_vm_tag(VMTag::kVMTagId); |
311 ASSERT(thread->store_buffer_block_ == NULL); | 310 ASSERT(thread->store_buffer_block_ == NULL); |
312 thread->StoreBufferAcquire(); | 311 thread->StoreBufferAcquire(); |
313 ASSERT(isolate->heap() != NULL); | 312 ASSERT(isolate->heap() != NULL); |
314 thread->heap_ = isolate->heap(); | 313 thread->heap_ = isolate->heap(); |
315 thread->Schedule(isolate); | 314 thread->Schedule(isolate); |
316 // TODO(koda): Migrate profiler interface to use Thread. | 315 thread->EnableThreadInterrupts(); |
317 Profiler::BeginExecution(isolate); | |
318 } | 316 } |
319 | 317 |
320 | 318 |
321 void Thread::ExitIsolate() { | 319 void Thread::ExitIsolate() { |
322 Thread* thread = Thread::Current(); | 320 Thread* thread = Thread::Current(); |
323 // TODO(koda): Audit callers; they should know whether they're in an isolate. | 321 // TODO(koda): Audit callers; they should know whether they're in an isolate. |
324 if (thread == NULL || thread->isolate() == NULL) return; | 322 if (thread == NULL || thread->isolate() == NULL) return; |
325 #if defined(DEBUG) | 323 #if defined(DEBUG) |
326 ASSERT(!thread->IsAnyReusableHandleScopeActive()); | 324 ASSERT(!thread->IsAnyReusableHandleScopeActive()); |
327 #endif // DEBUG | 325 #endif // DEBUG |
| 326 thread->DisableThreadInterrupts(); |
328 // Clear since GC will not visit the thread once it is unscheduled. | 327 // Clear since GC will not visit the thread once it is unscheduled. |
329 thread->ClearReusableHandles(); | 328 thread->ClearReusableHandles(); |
330 Isolate* isolate = thread->isolate(); | 329 Isolate* isolate = thread->isolate(); |
331 Profiler::EndExecution(isolate); | |
332 thread->Unschedule(); | 330 thread->Unschedule(); |
333 // TODO(koda): Move store_buffer_block_ into State. | 331 // TODO(koda): Move store_buffer_block_ into State. |
334 thread->StoreBufferRelease(); | 332 thread->StoreBufferRelease(); |
335 if (isolate->is_runnable()) { | 333 if (isolate->is_runnable()) { |
336 thread->set_vm_tag(VMTag::kIdleTagId); | 334 thread->set_vm_tag(VMTag::kIdleTagId); |
337 } else { | 335 } else { |
338 thread->set_vm_tag(VMTag::kLoadWaitTagId); | 336 thread->set_vm_tag(VMTag::kLoadWaitTagId); |
339 } | 337 } |
340 isolate->ClearMutatorThread(); | 338 isolate->ClearMutatorThread(); |
341 thread->isolate_ = NULL; | 339 thread->isolate_ = NULL; |
342 ASSERT(Isolate::Current() == NULL); | 340 ASSERT(Isolate::Current() == NULL); |
343 thread->heap_ = NULL; | 341 thread->heap_ = NULL; |
344 } | 342 } |
345 | 343 |
346 | 344 |
347 void Thread::EnterIsolateAsHelper(Isolate* isolate, bool bypass_safepoint) { | 345 void Thread::EnterIsolateAsHelper(Isolate* isolate, bool bypass_safepoint) { |
348 Thread* thread = Thread::Current(); | 346 Thread* thread = Thread::Current(); |
349 ASSERT(thread != NULL); | 347 ASSERT(thread != NULL); |
350 ASSERT(thread->isolate() == NULL); | 348 ASSERT(thread->isolate() == NULL); |
351 thread->isolate_ = isolate; | 349 thread->isolate_ = isolate; |
352 ASSERT(thread->store_buffer_block_ == NULL); | 350 ASSERT(thread->store_buffer_block_ == NULL); |
353 // TODO(koda): Use StoreBufferAcquire once we properly flush before Scavenge. | 351 // TODO(koda): Use StoreBufferAcquire once we properly flush before Scavenge. |
354 thread->store_buffer_block_ = | 352 thread->store_buffer_block_ = |
355 thread->isolate()->store_buffer()->PopEmptyBlock(); | 353 thread->isolate()->store_buffer()->PopEmptyBlock(); |
356 ASSERT(isolate->heap() != NULL); | 354 ASSERT(isolate->heap() != NULL); |
357 thread->heap_ = isolate->heap(); | 355 thread->heap_ = isolate->heap(); |
358 ASSERT(thread->thread_interrupt_callback_ == NULL); | |
359 ASSERT(thread->thread_interrupt_data_ == NULL); | |
360 // Do not update isolate->mutator_thread, but perform sanity check: | 356 // Do not update isolate->mutator_thread, but perform sanity check: |
361 // this thread should not be both the main mutator and helper. | 357 // this thread should not be both the main mutator and helper. |
362 ASSERT(!thread->IsMutatorThread()); | 358 ASSERT(!thread->IsMutatorThread()); |
363 thread->Schedule(isolate, bypass_safepoint); | 359 thread->Schedule(isolate, bypass_safepoint); |
| 360 thread->EnableThreadInterrupts(); |
364 } | 361 } |
365 | 362 |
366 | 363 |
367 void Thread::ExitIsolateAsHelper(bool bypass_safepoint) { | 364 void Thread::ExitIsolateAsHelper(bool bypass_safepoint) { |
368 Thread* thread = Thread::Current(); | 365 Thread* thread = Thread::Current(); |
| 366 thread->DisableThreadInterrupts(); |
369 Isolate* isolate = thread->isolate(); | 367 Isolate* isolate = thread->isolate(); |
370 ASSERT(isolate != NULL); | 368 ASSERT(isolate != NULL); |
371 thread->Unschedule(bypass_safepoint); | 369 thread->Unschedule(bypass_safepoint); |
372 // TODO(koda): Move store_buffer_block_ into State. | 370 // TODO(koda): Move store_buffer_block_ into State. |
373 thread->StoreBufferRelease(); | 371 thread->StoreBufferRelease(); |
374 thread->isolate_ = NULL; | 372 thread->isolate_ = NULL; |
375 thread->heap_ = NULL; | 373 thread->heap_ = NULL; |
376 ASSERT(!thread->IsMutatorThread()); | 374 ASSERT(!thread->IsMutatorThread()); |
377 } | 375 } |
378 | 376 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
422 void Thread::StoreBufferAcquire() { | 420 void Thread::StoreBufferAcquire() { |
423 store_buffer_block_ = isolate()->store_buffer()->PopNonFullBlock(); | 421 store_buffer_block_ = isolate()->store_buffer()->PopNonFullBlock(); |
424 } | 422 } |
425 | 423 |
426 | 424 |
427 bool Thread::IsMutatorThread() const { | 425 bool Thread::IsMutatorThread() const { |
428 return ((isolate_ != NULL) && (isolate_->mutator_thread() == this)); | 426 return ((isolate_ != NULL) && (isolate_->mutator_thread() == this)); |
429 } | 427 } |
430 | 428 |
431 | 429 |
| 430 bool Thread::IsExecutingDartCode() const { |
| 431 return (top_exit_frame_info() == 0) && |
| 432 (vm_tag() == VMTag::kDartTagId); |
| 433 } |
| 434 |
| 435 |
| 436 bool Thread::HasExitedDartCode() const { |
| 437 return (top_exit_frame_info() != 0) && |
| 438 (vm_tag() != VMTag::kDartTagId); |
| 439 } |
| 440 |
| 441 |
432 CHA* Thread::cha() const { | 442 CHA* Thread::cha() const { |
433 ASSERT(isolate_ != NULL); | 443 ASSERT(isolate_ != NULL); |
434 return cha_; | 444 return cha_; |
435 } | 445 } |
436 | 446 |
437 | 447 |
438 void Thread::set_cha(CHA* value) { | 448 void Thread::set_cha(CHA* value) { |
439 ASSERT(isolate_ != NULL); | 449 ASSERT(isolate_ != NULL); |
440 cha_ = value; | 450 cha_ = value; |
441 } | 451 } |
(...skipping 26 matching lines...) Expand all Loading... |
468 // Visit objects in thread specific handles area. | 478 // Visit objects in thread specific handles area. |
469 reusable_handles_.VisitObjectPointers(visitor); | 479 reusable_handles_.VisitObjectPointers(visitor); |
470 | 480 |
471 if (pending_functions_ != GrowableObjectArray::null()) { | 481 if (pending_functions_ != GrowableObjectArray::null()) { |
472 visitor->VisitPointer( | 482 visitor->VisitPointer( |
473 reinterpret_cast<RawObject**>(&pending_functions_)); | 483 reinterpret_cast<RawObject**>(&pending_functions_)); |
474 } | 484 } |
475 } | 485 } |
476 | 486 |
477 | 487 |
478 void Thread::SetThreadInterrupter(ThreadInterruptCallback callback, | 488 void Thread::DisableThreadInterrupts() { |
479 void* data) { | |
480 ASSERT(Thread::Current() == this); | 489 ASSERT(Thread::Current() == this); |
481 thread_interrupt_callback_ = callback; | 490 AtomicOperations::FetchAndIncrement(&thread_interrupt_disabled_); |
482 thread_interrupt_data_ = data; | |
483 } | 491 } |
484 | 492 |
485 | 493 |
486 bool Thread::IsThreadInterrupterEnabled(ThreadInterruptCallback* callback, | 494 void Thread::EnableThreadInterrupts() { |
487 void** data) const { | 495 ASSERT(Thread::Current() == this); |
488 #if defined(TARGET_OS_WINDOWS) | 496 uintptr_t old = |
489 // On Windows we expect this to be called from the thread interrupter thread. | 497 AtomicOperations::FetchAndDecrement(&thread_interrupt_disabled_); |
490 ASSERT(id() != OSThread::GetCurrentThreadId()); | 498 if (old == 1) { |
491 #else | 499 // We just decremented from 1 to 0. |
492 // On posix platforms, we expect this to be called from signal handler. | 500 // Make sure the thread interrupter is awake. |
493 ASSERT(id() == OSThread::GetCurrentThreadId()); | 501 ThreadInterrupter::WakeUp(); |
494 #endif | 502 } |
495 ASSERT(callback != NULL); | 503 if (old == 0) { |
496 ASSERT(data != NULL); | 504 // We just decremented from 0, this means we've got a mismatched pair |
497 *callback = thread_interrupt_callback_; | 505 // of calls to EnableThreadInterrupts and DisableThreadInterrupts. |
498 *data = thread_interrupt_data_; | 506 FATAL("Invalid call to Thread::EnableThreadInterrupts()"); |
499 return (*callback != NULL) && | 507 } |
500 (*data != NULL); | |
501 } | 508 } |
502 | 509 |
503 | 510 |
| 511 bool Thread::ThreadInterruptsEnabled() { |
| 512 return AtomicOperations::LoadRelaxed(&thread_interrupt_disabled_) == 0; |
| 513 } |
| 514 |
| 515 |
504 bool Thread::CanLoadFromThread(const Object& object) { | 516 bool Thread::CanLoadFromThread(const Object& object) { |
505 #define CHECK_OBJECT(type_name, member_name, expr, default_init_value) \ | 517 #define CHECK_OBJECT(type_name, member_name, expr, default_init_value) \ |
506 if (object.raw() == expr) return true; | 518 if (object.raw() == expr) return true; |
507 CACHED_VM_OBJECTS_LIST(CHECK_OBJECT) | 519 CACHED_VM_OBJECTS_LIST(CHECK_OBJECT) |
508 #undef CHECK_OBJECT | 520 #undef CHECK_OBJECT |
509 return false; | 521 return false; |
510 } | 522 } |
511 | 523 |
512 | 524 |
513 intptr_t Thread::OffsetFromThread(const Object& object) { | 525 intptr_t Thread::OffsetFromThread(const Object& object) { |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
565 | 577 |
566 Thread* ThreadIterator::Next() { | 578 Thread* ThreadIterator::Next() { |
567 ASSERT(Thread::thread_list_lock_ != NULL); | 579 ASSERT(Thread::thread_list_lock_ != NULL); |
568 ASSERT(Thread::thread_list_lock_->IsOwnedByCurrentThread()); | 580 ASSERT(Thread::thread_list_lock_->IsOwnedByCurrentThread()); |
569 Thread* current = next_; | 581 Thread* current = next_; |
570 next_ = next_->thread_list_next_; | 582 next_ = next_->thread_list_next_; |
571 return current; | 583 return current; |
572 } | 584 } |
573 | 585 |
574 | 586 |
| 587 DisableThreadInterruptsScope::DisableThreadInterruptsScope(Thread* thread) |
| 588 : StackResource(thread) { |
| 589 if (thread != NULL) { |
| 590 thread->DisableThreadInterrupts(); |
| 591 } |
| 592 } |
| 593 |
| 594 |
| 595 DisableThreadInterruptsScope::~DisableThreadInterruptsScope() { |
| 596 if (thread() != NULL) { |
| 597 thread()->EnableThreadInterrupts(); |
| 598 } |
| 599 } |
| 600 |
575 } // namespace dart | 601 } // namespace dart |
OLD | NEW |