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/collection-barrier.h" 6 7 #include "src/base/platform/mutex.h" 8 #include "src/base/platform/time.h" 9 #include "src/common/globals.h" 10 #include "src/execution/isolate.h" 11 #include "src/handles/handles.h" 12 #include "src/heap/gc-tracer.h" 13 #include "src/heap/heap-inl.h" 14 #include "src/heap/heap.h" 15 #include "src/heap/local-heap.h" 16 #include "src/heap/parked-scope.h" 17 18 namespace v8 { 19 namespace internal { 20 WasGCRequested()21bool CollectionBarrier::WasGCRequested() { 22 return collection_requested_.load(); 23 } 24 RequestGC()25void CollectionBarrier::RequestGC() { 26 base::MutexGuard guard(&mutex_); 27 bool was_already_requested = collection_requested_.exchange(true); 28 29 if (!was_already_requested) { 30 CHECK(!timer_.IsStarted()); 31 timer_.Start(); 32 } 33 } 34 35 class BackgroundCollectionInterruptTask : public CancelableTask { 36 public: BackgroundCollectionInterruptTask(Heap * heap)37 explicit BackgroundCollectionInterruptTask(Heap* heap) 38 : CancelableTask(heap->isolate()), heap_(heap) {} 39 40 ~BackgroundCollectionInterruptTask() override = default; 41 BackgroundCollectionInterruptTask(const BackgroundCollectionInterruptTask&) = 42 delete; 43 BackgroundCollectionInterruptTask& operator=( 44 const BackgroundCollectionInterruptTask&) = delete; 45 46 private: 47 // v8::internal::CancelableTask overrides. RunInternal()48 void RunInternal() override { heap_->CheckCollectionRequested(); } 49 50 Heap* heap_; 51 }; 52 NotifyShutdownRequested()53void CollectionBarrier::NotifyShutdownRequested() { 54 base::MutexGuard guard(&mutex_); 55 if (timer_.IsStarted()) timer_.Stop(); 56 shutdown_requested_ = true; 57 cv_wakeup_.NotifyAll(); 58 } 59 ResumeThreadsAwaitingCollection()60void CollectionBarrier::ResumeThreadsAwaitingCollection() { 61 base::MutexGuard guard(&mutex_); 62 collection_requested_.store(false); 63 block_for_collection_ = false; 64 cv_wakeup_.NotifyAll(); 65 } 66 AwaitCollectionBackground(LocalHeap * local_heap)67bool CollectionBarrier::AwaitCollectionBackground(LocalHeap* local_heap) { 68 bool first_thread; 69 70 { 71 // Update flag before parking this thread, this guarantees that the flag is 72 // set before the next GC. 73 base::MutexGuard guard(&mutex_); 74 if (shutdown_requested_) return false; 75 first_thread = !block_for_collection_; 76 block_for_collection_ = true; 77 CHECK(timer_.IsStarted()); 78 } 79 80 // The first thread needs to activate the stack guard and post the task. 81 if (first_thread) ActivateStackGuardAndPostTask(); 82 83 ParkedScope scope(local_heap); 84 base::MutexGuard guard(&mutex_); 85 86 while (block_for_collection_) { 87 if (shutdown_requested_) return false; 88 cv_wakeup_.Wait(&mutex_); 89 } 90 91 return true; 92 } 93 ActivateStackGuardAndPostTask()94void CollectionBarrier::ActivateStackGuardAndPostTask() { 95 Isolate* isolate = heap_->isolate(); 96 ExecutionAccess access(isolate); 97 isolate->stack_guard()->RequestGC(); 98 99 V8::GetCurrentPlatform() 100 ->GetForegroundTaskRunner(reinterpret_cast<v8::Isolate*>(isolate)) 101 ->PostTask(std::make_unique<BackgroundCollectionInterruptTask>(heap_)); 102 } 103 StopTimeToCollectionTimer()104void CollectionBarrier::StopTimeToCollectionTimer() { 105 if (collection_requested_.load()) { 106 base::MutexGuard guard(&mutex_); 107 // The first thread that requests the GC, starts the timer first and *then* 108 // parks itself. Since we are in a safepoint here, the timer is always 109 // initialized here already. 110 CHECK(timer_.IsStarted()); 111 base::TimeDelta delta = timer_.Elapsed(); 112 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.gc"), 113 "V8.GC.TimeToCollectionOnBackground", 114 TRACE_EVENT_SCOPE_THREAD, "duration", 115 delta.InMillisecondsF()); 116 heap_->isolate() 117 ->counters() 118 ->gc_time_to_collection_on_background() 119 ->AddTimedSample(delta); 120 timer_.Stop(); 121 } 122 } 123 124 } // namespace internal 125 } // namespace v8 126