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