| // Copyright 2020 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/heap/collection-barrier.h" |
| |
| #include "src/base/platform/time.h" |
| #include "src/heap/gc-tracer.h" |
| #include "src/heap/heap-inl.h" |
| #include "src/heap/heap.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| void CollectionBarrier::ResumeThreadsAwaitingCollection() { |
| base::MutexGuard guard(&mutex_); |
| ClearCollectionRequested(); |
| cond_.NotifyAll(); |
| } |
| |
| void CollectionBarrier::ShutdownRequested() { |
| base::MutexGuard guard(&mutex_); |
| if (timer_.IsStarted()) timer_.Stop(); |
| state_.store(RequestState::kShutdown); |
| cond_.NotifyAll(); |
| } |
| |
| class BackgroundCollectionInterruptTask : public CancelableTask { |
| public: |
| explicit BackgroundCollectionInterruptTask(Heap* heap) |
| : CancelableTask(heap->isolate()), heap_(heap) {} |
| |
| ~BackgroundCollectionInterruptTask() override = default; |
| |
| private: |
| // v8::internal::CancelableTask overrides. |
| void RunInternal() override { heap_->CheckCollectionRequested(); } |
| |
| Heap* heap_; |
| DISALLOW_COPY_AND_ASSIGN(BackgroundCollectionInterruptTask); |
| }; |
| |
| void CollectionBarrier::AwaitCollectionBackground() { |
| bool first; |
| |
| { |
| base::MutexGuard guard(&mutex_); |
| first = FirstCollectionRequest(); |
| if (first) timer_.Start(); |
| } |
| |
| if (first) { |
| // This is the first background thread requesting collection, ask the main |
| // thread for GC. |
| ActivateStackGuardAndPostTask(); |
| } |
| |
| BlockUntilCollected(); |
| } |
| |
| void CollectionBarrier::StopTimeToCollectionTimer() { |
| base::MutexGuard guard(&mutex_); |
| RequestState old_state = state_.exchange(RequestState::kCollectionStarted, |
| std::memory_order_relaxed); |
| if (old_state == RequestState::kCollectionRequested) { |
| DCHECK(timer_.IsStarted()); |
| base::TimeDelta delta = timer_.Elapsed(); |
| TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.gc"), |
| "V8.TimeToCollection", TRACE_EVENT_SCOPE_THREAD, |
| "duration", delta.InMillisecondsF()); |
| heap_->isolate()->counters()->time_to_collection()->AddTimedSample(delta); |
| timer_.Stop(); |
| } else { |
| DCHECK_EQ(old_state, RequestState::kDefault); |
| DCHECK(!timer_.IsStarted()); |
| } |
| } |
| |
| void CollectionBarrier::ActivateStackGuardAndPostTask() { |
| Isolate* isolate = heap_->isolate(); |
| ExecutionAccess access(isolate); |
| isolate->stack_guard()->RequestGC(); |
| auto taskrunner = V8::GetCurrentPlatform()->GetForegroundTaskRunner( |
| reinterpret_cast<v8::Isolate*>(isolate)); |
| taskrunner->PostTask( |
| std::make_unique<BackgroundCollectionInterruptTask>(heap_)); |
| } |
| |
| void CollectionBarrier::BlockUntilCollected() { |
| TRACE_BACKGROUND_GC(heap_->tracer(), |
| GCTracer::BackgroundScope::BACKGROUND_COLLECTION); |
| base::MutexGuard guard(&mutex_); |
| |
| while (CollectionRequested()) { |
| cond_.Wait(&mutex_); |
| } |
| } |
| |
| } // namespace internal |
| } // namespace v8 |