safepoint.cc 4.15 KB
Newer Older
1 2 3 4 5
// 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/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 12 13 14 15
#include "src/heap/local-heap.h"

namespace v8 {
namespace internal {

16
GlobalSafepoint::GlobalSafepoint(Heap* heap)
17
    : heap_(heap), local_heaps_head_(nullptr), active_safepoint_scopes_(0) {}
18

19 20 21 22
void GlobalSafepoint::EnterSafepointScope() {
  if (!FLAG_local_heaps) return;

  if (++active_safepoint_scopes_ > 1) return;
23

24
  TimedHistogramScope timer(heap_->isolate()->counters()->time_to_safepoint());
25 26
  TRACE_GC(heap_->tracer(), GCTracer::Scope::STOP_THE_WORLD);

27
  local_heaps_mutex_.Lock();
28
  local_heap_of_this_thread_ = LocalHeap::Current();
29 30 31

  barrier_.Arm();

32
  for (LocalHeap* current = local_heaps_head_; current;
33
       current = current->next_) {
34 35 36
    if (current == local_heap_of_this_thread_) {
      continue;
    }
37 38 39
    current->RequestSafepoint();
  }

40
  for (LocalHeap* current = local_heaps_head_; current;
41
       current = current->next_) {
42 43 44
    if (current == local_heap_of_this_thread_) {
      continue;
    }
45 46 47 48 49 50 51 52
    current->state_mutex_.Lock();

    while (current->state_ == LocalHeap::ThreadState::Running) {
      current->state_change_.Wait(&current->state_mutex_);
    }
  }
}

53 54 55 56 57
void GlobalSafepoint::LeaveSafepointScope() {
  if (!FLAG_local_heaps) return;

  DCHECK_GT(active_safepoint_scopes_, 0);
  if (--active_safepoint_scopes_ > 0) return;
58

59 60
  DCHECK_EQ(local_heap_of_this_thread_, LocalHeap::Current());

61
  for (LocalHeap* current = local_heaps_head_; current;
62
       current = current->next_) {
63 64 65
    if (current == local_heap_of_this_thread_) {
      continue;
    }
66 67 68 69 70
    current->state_mutex_.Unlock();
  }

  barrier_.Disarm();

71
  local_heap_of_this_thread_ = nullptr;
72
  local_heaps_mutex_.Unlock();
73 74
}

75
void GlobalSafepoint::EnterFromThread(LocalHeap* local_heap) {
76 77
  {
    base::MutexGuard guard(&local_heap->state_mutex_);
78
    DCHECK_EQ(local_heap->state_, LocalHeap::ThreadState::Running);
79 80 81 82 83 84 85 86 87 88 89 90
    local_heap->state_ = LocalHeap::ThreadState::Safepoint;
    local_heap->state_change_.NotifyAll();
  }

  barrier_.Wait();

  {
    base::MutexGuard guard(&local_heap->state_mutex_);
    local_heap->state_ = LocalHeap::ThreadState::Running;
  }
}

91
void GlobalSafepoint::Barrier::Arm() {
92 93 94 95 96
  base::MutexGuard guard(&mutex_);
  CHECK(!armed_);
  armed_ = true;
}

97
void GlobalSafepoint::Barrier::Disarm() {
98 99 100 101 102 103
  base::MutexGuard guard(&mutex_);
  CHECK(armed_);
  armed_ = false;
  cond_.NotifyAll();
}

104
void GlobalSafepoint::Barrier::Wait() {
105 106 107 108 109 110 111
  base::MutexGuard guard(&mutex_);
  while (armed_) {
    cond_.Wait(&mutex_);
  }
}

SafepointScope::SafepointScope(Heap* heap) : safepoint_(heap->safepoint()) {
112
  safepoint_->EnterSafepointScope();
113 114
}

115
SafepointScope::~SafepointScope() { safepoint_->LeaveSafepointScope(); }
116

117
void GlobalSafepoint::AddLocalHeap(LocalHeap* local_heap) {
118 119 120 121 122 123 124
  base::MutexGuard guard(&local_heaps_mutex_);
  if (local_heaps_head_) local_heaps_head_->prev_ = local_heap;
  local_heap->prev_ = nullptr;
  local_heap->next_ = local_heaps_head_;
  local_heaps_head_ = local_heap;
}

125
void GlobalSafepoint::RemoveLocalHeap(LocalHeap* local_heap) {
126 127 128 129 130 131 132 133
  base::MutexGuard guard(&local_heaps_mutex_);
  if (local_heap->next_) local_heap->next_->prev_ = local_heap->prev_;
  if (local_heap->prev_)
    local_heap->prev_->next_ = local_heap->next_;
  else
    local_heaps_head_ = local_heap->next_;
}

134
bool GlobalSafepoint::ContainsLocalHeap(LocalHeap* local_heap) {
135 136 137 138 139 140 141 142 143 144 145
  base::MutexGuard guard(&local_heaps_mutex_);
  LocalHeap* current = local_heaps_head_;

  while (current) {
    if (current == local_heap) return true;
    current = current->next_;
  }

  return false;
}

146
bool GlobalSafepoint::ContainsAnyLocalHeap() {
147 148 149 150
  base::MutexGuard guard(&local_heaps_mutex_);
  return local_heaps_head_ != nullptr;
}

151
void GlobalSafepoint::Iterate(RootVisitor* visitor) {
152
  DCHECK(IsActive());
153 154 155 156 157 158
  for (LocalHeap* current = local_heaps_head_; current;
       current = current->next_) {
    current->handles()->Iterate(visitor);
  }
}

159 160
}  // namespace internal
}  // namespace v8