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