collection-barrier.cc 3.7 KB
Newer Older
1 2 3 4 5 6
// 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"

7
#include "src/base/platform/mutex.h"
8
#include "src/base/platform/time.h"
9
#include "src/common/globals.h"
10 11
#include "src/execution/isolate.h"
#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 16
#include "src/heap/local-heap.h"
#include "src/heap/parked-scope.h"
17 18 19 20

namespace v8 {
namespace internal {

21 22
bool CollectionBarrier::WasGCRequested() {
  return collection_requested_.load();
23 24
}

25
void CollectionBarrier::RequestGC() {
26
  base::MutexGuard guard(&mutex_);
27
  bool was_already_requested = collection_requested_.exchange(true);
28

29 30 31 32
  if (!was_already_requested) {
    CHECK(!timer_.IsStarted());
    timer_.Start();
  }
33 34 35 36 37 38 39 40
}

class BackgroundCollectionInterruptTask : public CancelableTask {
 public:
  explicit BackgroundCollectionInterruptTask(Heap* heap)
      : CancelableTask(heap->isolate()), heap_(heap) {}

  ~BackgroundCollectionInterruptTask() override = default;
41 42 43 44
  BackgroundCollectionInterruptTask(const BackgroundCollectionInterruptTask&) =
      delete;
  BackgroundCollectionInterruptTask& operator=(
      const BackgroundCollectionInterruptTask&) = delete;
45 46 47 48 49 50 51 52

 private:
  // v8::internal::CancelableTask overrides.
  void RunInternal() override { heap_->CheckCollectionRequested(); }

  Heap* heap_;
};

53 54 55 56 57 58 59 60 61 62 63 64 65 66
void CollectionBarrier::NotifyShutdownRequested() {
  base::MutexGuard guard(&mutex_);
  if (timer_.IsStarted()) timer_.Stop();
  shutdown_requested_ = true;
  cv_wakeup_.NotifyAll();
}

void CollectionBarrier::ResumeThreadsAwaitingCollection() {
  base::MutexGuard guard(&mutex_);
  collection_requested_.store(false);
  block_for_collection_ = false;
  cv_wakeup_.NotifyAll();
}

67
bool CollectionBarrier::AwaitCollectionBackground(LocalHeap* local_heap) {
68 69 70 71 72 73
  bool first_thread;

  {
    // Update flag before parking this thread, this guarantees that the flag is
    // set before the next GC.
    base::MutexGuard guard(&mutex_);
74
    if (shutdown_requested_) return false;
75 76 77 78 79 80 81 82
    first_thread = !block_for_collection_;
    block_for_collection_ = true;
    CHECK(timer_.IsStarted());
  }

  // The first thread needs to activate the stack guard and post the task.
  if (first_thread) ActivateStackGuardAndPostTask();

83 84
  ParkedScope scope(local_heap);
  base::MutexGuard guard(&mutex_);
85

86
  while (block_for_collection_) {
87 88
    if (shutdown_requested_) return false;
    cv_wakeup_.Wait(&mutex_);
89 90
  }

91
  return true;
92 93
}

94 95 96 97
void CollectionBarrier::ActivateStackGuardAndPostTask() {
  Isolate* isolate = heap_->isolate();
  ExecutionAccess access(isolate);
  isolate->stack_guard()->RequestGC();
98

99 100 101 102 103 104 105
  V8::GetCurrentPlatform()
      ->GetForegroundTaskRunner(reinterpret_cast<v8::Isolate*>(isolate))
      ->PostTask(std::make_unique<BackgroundCollectionInterruptTask>(heap_));
}

void CollectionBarrier::StopTimeToCollectionTimer() {
  if (collection_requested_.load()) {
106
    base::MutexGuard guard(&mutex_);
107 108 109
    // The first thread that requests the GC, starts the timer first and *then*
    // parks itself. Since we are in a safepoint here, the timer is always
    // initialized here already.
110
    CHECK(timer_.IsStarted());
111 112
    base::TimeDelta delta = timer_.Elapsed();
    TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.gc"),
113 114 115 116 117 118 119
                         "V8.GC.TimeToCollectionOnBackground",
                         TRACE_EVENT_SCOPE_THREAD, "duration",
                         delta.InMillisecondsF());
    heap_->isolate()
        ->counters()
        ->gc_time_to_collection_on_background()
        ->AddTimedSample(delta);
120 121
    timer_.Stop();
  }
122 123 124 125
}

}  // namespace internal
}  // namespace v8