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 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
207 #define REUSABLE_HANDLE_SCOPE_INIT(object) | 207 #define REUSABLE_HANDLE_SCOPE_INIT(object) |
208 #endif // defined(DEBUG) | 208 #endif // defined(DEBUG) |
209 | 209 |
210 #define REUSABLE_HANDLE_INITIALIZERS(object) \ | 210 #define REUSABLE_HANDLE_INITIALIZERS(object) \ |
211 object##_handle_(NULL), | 211 object##_handle_(NULL), |
212 | 212 |
213 | 213 |
214 Thread::Thread(bool init_vm_constants) | 214 Thread::Thread(bool init_vm_constants) |
215 : id_(OSThread::GetCurrentThreadId()), | 215 : id_(OSThread::GetCurrentThreadId()), |
216 join_id_(OSThread::GetCurrentThreadJoinId()), | 216 join_id_(OSThread::GetCurrentThreadJoinId()), |
217 thread_interrupt_callback_(NULL), | 217 thread_interrupt_disabled_(1), // Thread interrupts disabled by default. |
218 thread_interrupt_data_(NULL), | |
219 isolate_(NULL), | 218 isolate_(NULL), |
220 heap_(NULL), | 219 heap_(NULL), |
221 timeline_block_(NULL), | 220 timeline_block_(NULL), |
222 store_buffer_block_(NULL), | 221 store_buffer_block_(NULL), |
223 log_(new class Log()), | 222 log_(new class Log()), |
224 REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_INITIALIZERS) | 223 REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_INITIALIZERS) |
225 REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_SCOPE_INIT) | 224 REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_SCOPE_INIT) |
226 reusable_handles_(), | 225 reusable_handles_(), |
227 cha_(NULL), | 226 cha_(NULL), |
228 deopt_id_(0), | 227 deopt_id_(0), |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
324 ASSERT(thread->isolate() == NULL); | 323 ASSERT(thread->isolate() == NULL); |
325 ASSERT(!isolate->HasMutatorThread()); | 324 ASSERT(!isolate->HasMutatorThread()); |
326 thread->isolate_ = isolate; | 325 thread->isolate_ = isolate; |
327 isolate->MakeCurrentThreadMutator(thread); | 326 isolate->MakeCurrentThreadMutator(thread); |
328 thread->set_vm_tag(VMTag::kVMTagId); | 327 thread->set_vm_tag(VMTag::kVMTagId); |
329 ASSERT(thread->store_buffer_block_ == NULL); | 328 ASSERT(thread->store_buffer_block_ == NULL); |
330 thread->StoreBufferAcquire(); | 329 thread->StoreBufferAcquire(); |
331 ASSERT(isolate->heap() != NULL); | 330 ASSERT(isolate->heap() != NULL); |
332 thread->heap_ = isolate->heap(); | 331 thread->heap_ = isolate->heap(); |
333 thread->Schedule(isolate); | 332 thread->Schedule(isolate); |
334 // TODO(koda): Migrate profiler interface to use Thread. | 333 thread->EnableThreadInterrupts(); |
335 Profiler::BeginExecution(isolate); | |
336 } | 334 } |
337 | 335 |
338 | 336 |
339 void Thread::ExitIsolate() { | 337 void Thread::ExitIsolate() { |
340 Thread* thread = Thread::Current(); | 338 Thread* thread = Thread::Current(); |
341 // TODO(koda): Audit callers; they should know whether they're in an isolate. | 339 // TODO(koda): Audit callers; they should know whether they're in an isolate. |
342 if (thread == NULL || thread->isolate() == NULL) return; | 340 if (thread == NULL || thread->isolate() == NULL) return; |
343 #if defined(DEBUG) | 341 #if defined(DEBUG) |
344 ASSERT(!thread->IsAnyReusableHandleScopeActive()); | 342 ASSERT(!thread->IsAnyReusableHandleScopeActive()); |
345 #endif // DEBUG | 343 #endif // DEBUG |
| 344 thread->DisableThreadInterrupts(); |
346 // Clear since GC will not visit the thread once it is unscheduled. | 345 // Clear since GC will not visit the thread once it is unscheduled. |
347 thread->ClearReusableHandles(); | 346 thread->ClearReusableHandles(); |
348 Isolate* isolate = thread->isolate(); | 347 Isolate* isolate = thread->isolate(); |
349 Profiler::EndExecution(isolate); | |
350 thread->Unschedule(); | 348 thread->Unschedule(); |
351 // TODO(koda): Move store_buffer_block_ into State. | 349 // TODO(koda): Move store_buffer_block_ into State. |
352 thread->StoreBufferRelease(); | 350 thread->StoreBufferRelease(); |
353 if (isolate->is_runnable()) { | 351 if (isolate->is_runnable()) { |
354 thread->set_vm_tag(VMTag::kIdleTagId); | 352 thread->set_vm_tag(VMTag::kIdleTagId); |
355 } else { | 353 } else { |
356 thread->set_vm_tag(VMTag::kLoadWaitTagId); | 354 thread->set_vm_tag(VMTag::kLoadWaitTagId); |
357 } | 355 } |
358 isolate->ClearMutatorThread(); | 356 isolate->ClearMutatorThread(); |
359 thread->isolate_ = NULL; | 357 thread->isolate_ = NULL; |
360 ASSERT(Isolate::Current() == NULL); | 358 ASSERT(Isolate::Current() == NULL); |
361 thread->heap_ = NULL; | 359 thread->heap_ = NULL; |
362 } | 360 } |
363 | 361 |
364 | 362 |
365 void Thread::EnterIsolateAsHelper(Isolate* isolate, bool bypass_safepoint) { | 363 void Thread::EnterIsolateAsHelper(Isolate* isolate, bool bypass_safepoint) { |
366 Thread* thread = Thread::Current(); | 364 Thread* thread = Thread::Current(); |
367 ASSERT(thread != NULL); | 365 ASSERT(thread != NULL); |
368 ASSERT(thread->isolate() == NULL); | 366 ASSERT(thread->isolate() == NULL); |
369 thread->isolate_ = isolate; | 367 thread->isolate_ = isolate; |
370 ASSERT(thread->store_buffer_block_ == NULL); | 368 ASSERT(thread->store_buffer_block_ == NULL); |
371 // TODO(koda): Use StoreBufferAcquire once we properly flush before Scavenge. | 369 // TODO(koda): Use StoreBufferAcquire once we properly flush before Scavenge. |
372 thread->store_buffer_block_ = | 370 thread->store_buffer_block_ = |
373 thread->isolate()->store_buffer()->PopEmptyBlock(); | 371 thread->isolate()->store_buffer()->PopEmptyBlock(); |
374 ASSERT(isolate->heap() != NULL); | 372 ASSERT(isolate->heap() != NULL); |
375 thread->heap_ = isolate->heap(); | 373 thread->heap_ = isolate->heap(); |
376 ASSERT(thread->thread_interrupt_callback_ == NULL); | |
377 ASSERT(thread->thread_interrupt_data_ == NULL); | |
378 // Do not update isolate->mutator_thread, but perform sanity check: | 374 // Do not update isolate->mutator_thread, but perform sanity check: |
379 // this thread should not be both the main mutator and helper. | 375 // this thread should not be both the main mutator and helper. |
380 ASSERT(!thread->IsMutatorThread()); | 376 ASSERT(!thread->IsMutatorThread()); |
381 thread->Schedule(isolate, bypass_safepoint); | 377 thread->Schedule(isolate, bypass_safepoint); |
| 378 thread->EnableThreadInterrupts(); |
382 } | 379 } |
383 | 380 |
384 | 381 |
385 void Thread::ExitIsolateAsHelper(bool bypass_safepoint) { | 382 void Thread::ExitIsolateAsHelper(bool bypass_safepoint) { |
386 Thread* thread = Thread::Current(); | 383 Thread* thread = Thread::Current(); |
| 384 thread->DisableThreadInterrupts(); |
387 Isolate* isolate = thread->isolate(); | 385 Isolate* isolate = thread->isolate(); |
388 ASSERT(isolate != NULL); | 386 ASSERT(isolate != NULL); |
389 thread->Unschedule(bypass_safepoint); | 387 thread->Unschedule(bypass_safepoint); |
390 // TODO(koda): Move store_buffer_block_ into State. | 388 // TODO(koda): Move store_buffer_block_ into State. |
391 thread->StoreBufferRelease(); | 389 thread->StoreBufferRelease(); |
392 thread->isolate_ = NULL; | 390 thread->isolate_ = NULL; |
393 thread->heap_ = NULL; | 391 thread->heap_ = NULL; |
394 ASSERT(!thread->IsMutatorThread()); | 392 ASSERT(!thread->IsMutatorThread()); |
395 } | 393 } |
396 | 394 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
440 void Thread::StoreBufferAcquire() { | 438 void Thread::StoreBufferAcquire() { |
441 store_buffer_block_ = isolate()->store_buffer()->PopNonFullBlock(); | 439 store_buffer_block_ = isolate()->store_buffer()->PopNonFullBlock(); |
442 } | 440 } |
443 | 441 |
444 | 442 |
445 bool Thread::IsMutatorThread() const { | 443 bool Thread::IsMutatorThread() const { |
446 return ((isolate_ != NULL) && (isolate_->mutator_thread() == this)); | 444 return ((isolate_ != NULL) && (isolate_->mutator_thread() == this)); |
447 } | 445 } |
448 | 446 |
449 | 447 |
| 448 bool Thread::IsExecutingDartCode() const { |
| 449 return (top_exit_frame_info() == 0) && |
| 450 (vm_tag() == VMTag::kDartTagId); |
| 451 } |
| 452 |
| 453 |
| 454 bool Thread::HasExitedDartCode() const { |
| 455 return (top_exit_frame_info() != 0) && |
| 456 (vm_tag() != VMTag::kDartTagId); |
| 457 } |
| 458 |
| 459 |
450 CHA* Thread::cha() const { | 460 CHA* Thread::cha() const { |
451 ASSERT(isolate_ != NULL); | 461 ASSERT(isolate_ != NULL); |
452 return cha_; | 462 return cha_; |
453 } | 463 } |
454 | 464 |
455 | 465 |
456 void Thread::set_cha(CHA* value) { | 466 void Thread::set_cha(CHA* value) { |
457 ASSERT(isolate_ != NULL); | 467 ASSERT(isolate_ != NULL); |
458 cha_ = value; | 468 cha_ = value; |
459 } | 469 } |
(...skipping 26 matching lines...) Expand all Loading... |
486 // Visit objects in thread specific handles area. | 496 // Visit objects in thread specific handles area. |
487 reusable_handles_.VisitObjectPointers(visitor); | 497 reusable_handles_.VisitObjectPointers(visitor); |
488 | 498 |
489 if (pending_functions_ != GrowableObjectArray::null()) { | 499 if (pending_functions_ != GrowableObjectArray::null()) { |
490 visitor->VisitPointer( | 500 visitor->VisitPointer( |
491 reinterpret_cast<RawObject**>(&pending_functions_)); | 501 reinterpret_cast<RawObject**>(&pending_functions_)); |
492 } | 502 } |
493 } | 503 } |
494 | 504 |
495 | 505 |
496 void Thread::SetThreadInterrupter(ThreadInterruptCallback callback, | 506 void Thread::DisableThreadInterrupts() { |
497 void* data) { | |
498 ASSERT(Thread::Current() == this); | 507 ASSERT(Thread::Current() == this); |
499 thread_interrupt_callback_ = callback; | 508 AtomicOperations::FetchAndIncrement(&thread_interrupt_disabled_); |
500 thread_interrupt_data_ = data; | |
501 } | 509 } |
502 | 510 |
503 | 511 |
504 bool Thread::IsThreadInterrupterEnabled(ThreadInterruptCallback* callback, | 512 void Thread::EnableThreadInterrupts() { |
505 void** data) const { | 513 ASSERT(Thread::Current() == this); |
506 #if defined(TARGET_OS_WINDOWS) | 514 uintptr_t old = |
507 // On Windows we expect this to be called from the thread interrupter thread. | 515 AtomicOperations::FetchAndDecrement(&thread_interrupt_disabled_); |
508 ASSERT(id() != OSThread::GetCurrentThreadId()); | 516 if (old == 1) { |
509 #else | 517 // We just decremented from 1 to 0. |
510 // On posix platforms, we expect this to be called from signal handler. | 518 // Make sure the thread interrupter is awake. |
511 ASSERT(id() == OSThread::GetCurrentThreadId()); | 519 ThreadInterrupter::WakeUp(); |
512 #endif | 520 } |
513 ASSERT(callback != NULL); | 521 if (old == 0) { |
514 ASSERT(data != NULL); | 522 // We just decremented from 0, this means we've got a mismatched pair |
515 *callback = thread_interrupt_callback_; | 523 // of calls to EnableThreadInterrupts and DisableThreadInterrupts. |
516 *data = thread_interrupt_data_; | 524 FATAL("Invalid call to Thread::EnableThreadInterrupts()"); |
517 return (*callback != NULL) && | 525 } |
518 (*data != NULL); | |
519 } | 526 } |
520 | 527 |
521 | 528 |
| 529 bool Thread::ThreadInterruptsEnabled() { |
| 530 return AtomicOperations::LoadRelaxed(&thread_interrupt_disabled_) == 0; |
| 531 } |
| 532 |
| 533 |
522 bool Thread::CanLoadFromThread(const Object& object) { | 534 bool Thread::CanLoadFromThread(const Object& object) { |
523 #define CHECK_OBJECT(type_name, member_name, expr, default_init_value) \ | 535 #define CHECK_OBJECT(type_name, member_name, expr, default_init_value) \ |
524 if (object.raw() == expr) return true; | 536 if (object.raw() == expr) return true; |
525 CACHED_VM_OBJECTS_LIST(CHECK_OBJECT) | 537 CACHED_VM_OBJECTS_LIST(CHECK_OBJECT) |
526 #undef CHECK_OBJECT | 538 #undef CHECK_OBJECT |
527 return false; | 539 return false; |
528 } | 540 } |
529 | 541 |
530 | 542 |
531 intptr_t Thread::OffsetFromThread(const Object& object) { | 543 intptr_t Thread::OffsetFromThread(const Object& object) { |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
583 | 595 |
584 Thread* ThreadIterator::Next() { | 596 Thread* ThreadIterator::Next() { |
585 ASSERT(Thread::thread_list_lock_ != NULL); | 597 ASSERT(Thread::thread_list_lock_ != NULL); |
586 ASSERT(Thread::thread_list_lock_->IsOwnedByCurrentThread()); | 598 ASSERT(Thread::thread_list_lock_->IsOwnedByCurrentThread()); |
587 Thread* current = next_; | 599 Thread* current = next_; |
588 next_ = next_->thread_list_next_; | 600 next_ = next_->thread_list_next_; |
589 return current; | 601 return current; |
590 } | 602 } |
591 | 603 |
592 | 604 |
| 605 DisableThreadInterruptsScope::DisableThreadInterruptsScope(Thread* thread) |
| 606 : StackResource(thread) { |
| 607 if (thread != NULL) { |
| 608 thread->DisableThreadInterrupts(); |
| 609 } |
| 610 } |
| 611 |
| 612 |
| 613 DisableThreadInterruptsScope::~DisableThreadInterruptsScope() { |
| 614 if (thread() != NULL) { |
| 615 thread()->EnableThreadInterrupts(); |
| 616 } |
| 617 } |
| 618 |
593 } // namespace dart | 619 } // namespace dart |
OLD | NEW |