1 // Copyright 2020 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/heap/safepoint.h" 6 7 #include "src/handles/local-handles.h" 8 #include "src/handles/persistent-handles.h" 9 #include "src/heap/gc-tracer.h" 10 #include "src/heap/heap-inl.h" 11 #include "src/heap/local-heap.h" 12 13 namespace v8 { 14 namespace internal { 15 GlobalSafepoint(Heap * heap)16GlobalSafepoint::GlobalSafepoint(Heap* heap) 17 : heap_(heap), local_heaps_head_(nullptr), active_safepoint_scopes_(0) {} 18 EnterSafepointScope()19void GlobalSafepoint::EnterSafepointScope() { 20 if (!FLAG_local_heaps) return; 21 22 if (++active_safepoint_scopes_ > 1) return; 23 24 TimedHistogramScope timer(heap_->isolate()->counters()->stop_the_world()); 25 TRACE_GC(heap_->tracer(), GCTracer::Scope::STOP_THE_WORLD); 26 27 local_heaps_mutex_.Lock(); 28 local_heap_of_this_thread_ = LocalHeap::Current(); 29 30 barrier_.Arm(); 31 32 for (LocalHeap* current = local_heaps_head_; current; 33 current = current->next_) { 34 if (current == local_heap_of_this_thread_) { 35 continue; 36 } 37 current->RequestSafepoint(); 38 } 39 40 for (LocalHeap* current = local_heaps_head_; current; 41 current = current->next_) { 42 if (current == local_heap_of_this_thread_) { 43 DCHECK(current->is_main_thread()); 44 continue; 45 } 46 DCHECK(!current->is_main_thread()); 47 current->state_mutex_.Lock(); 48 49 while (current->state_ == LocalHeap::ThreadState::Running) { 50 current->state_change_.Wait(¤t->state_mutex_); 51 } 52 } 53 } 54 LeaveSafepointScope()55void GlobalSafepoint::LeaveSafepointScope() { 56 if (!FLAG_local_heaps) return; 57 58 DCHECK_GT(active_safepoint_scopes_, 0); 59 if (--active_safepoint_scopes_ > 0) return; 60 61 DCHECK_EQ(local_heap_of_this_thread_, LocalHeap::Current()); 62 63 for (LocalHeap* current = local_heaps_head_; current; 64 current = current->next_) { 65 if (current == local_heap_of_this_thread_) { 66 continue; 67 } 68 current->state_mutex_.Unlock(); 69 } 70 71 barrier_.Disarm(); 72 73 local_heap_of_this_thread_ = nullptr; 74 local_heaps_mutex_.Unlock(); 75 } 76 EnterFromThread(LocalHeap * local_heap)77void GlobalSafepoint::EnterFromThread(LocalHeap* local_heap) { 78 { 79 base::MutexGuard guard(&local_heap->state_mutex_); 80 DCHECK_EQ(local_heap->state_, LocalHeap::ThreadState::Running); 81 local_heap->state_ = LocalHeap::ThreadState::Safepoint; 82 local_heap->state_change_.NotifyAll(); 83 } 84 85 barrier_.Wait(); 86 87 { 88 base::MutexGuard guard(&local_heap->state_mutex_); 89 local_heap->state_ = LocalHeap::ThreadState::Running; 90 } 91 } 92 Arm()93void GlobalSafepoint::Barrier::Arm() { 94 base::MutexGuard guard(&mutex_); 95 CHECK(!armed_); 96 armed_ = true; 97 } 98 Disarm()99void GlobalSafepoint::Barrier::Disarm() { 100 base::MutexGuard guard(&mutex_); 101 CHECK(armed_); 102 armed_ = false; 103 cond_.NotifyAll(); 104 } 105 Wait()106void GlobalSafepoint::Barrier::Wait() { 107 base::MutexGuard guard(&mutex_); 108 while (armed_) { 109 cond_.Wait(&mutex_); 110 } 111 } 112 SafepointScope(Heap * heap)113SafepointScope::SafepointScope(Heap* heap) : safepoint_(heap->safepoint()) { 114 safepoint_->EnterSafepointScope(); 115 } 116 ~SafepointScope()117SafepointScope::~SafepointScope() { safepoint_->LeaveSafepointScope(); } 118 ContainsLocalHeap(LocalHeap * local_heap)119bool GlobalSafepoint::ContainsLocalHeap(LocalHeap* local_heap) { 120 base::MutexGuard guard(&local_heaps_mutex_); 121 LocalHeap* current = local_heaps_head_; 122 123 while (current) { 124 if (current == local_heap) return true; 125 current = current->next_; 126 } 127 128 return false; 129 } 130 ContainsAnyLocalHeap()131bool GlobalSafepoint::ContainsAnyLocalHeap() { 132 base::MutexGuard guard(&local_heaps_mutex_); 133 return local_heaps_head_ != nullptr; 134 } 135 Iterate(RootVisitor * visitor)136void GlobalSafepoint::Iterate(RootVisitor* visitor) { 137 DCHECK(IsActive()); 138 for (LocalHeap* current = local_heaps_head_; current; 139 current = current->next_) { 140 current->handles()->Iterate(visitor); 141 } 142 } 143 144 } // namespace internal 145 } // namespace v8 146