v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
safepoint.cc
Go to the documentation of this file.
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
6
7#include <atomic>
8#include <vector>
9
10#include "src/base/logging.h"
12#include "src/common/globals.h"
14#include "src/handles/handles.h"
18#include "src/heap/gc-tracer.h"
19#include "src/heap/heap-inl.h"
20#include "src/heap/heap.h"
24#include "src/objects/objects.h"
25
26namespace v8 {
27namespace internal {
28
30
32 // Safepoints need to be initiated on some main thread.
33 DCHECK_NULL(LocalHeap::Current());
34 DCHECK(AllowGarbageCollection::IsAllowed());
35
36 LockMutex(isolate()->main_thread_local_heap());
37 if (++active_safepoint_scopes_ > 1) return;
38
39 // Local safepoint can only be initiated on the isolate's main thread.
40 DCHECK_EQ(ThreadId::Current(), isolate()->thread_id());
41
42 TimedHistogramScope timer(isolate()->counters()->gc_time_to_safepoint());
43 TRACE_GC(heap_->tracer(), GCTracer::Scope::TIME_TO_SAFEPOINT);
44
45 barrier_.Arm();
46 RunningLocalHeaps running_local_heaps;
49}
50
52 public:
53 explicit PerClientSafepointData(Isolate* isolate) : isolate_(isolate) {}
54
55 void set_locked() { locked_ = true; }
56
57 IsolateSafepoint* safepoint() const { return heap()->safepoint(); }
58 Heap* heap() const { return isolate_->heap(); }
59 Isolate* isolate() const { return isolate_; }
60
61 bool is_locked() const { return locked_; }
62
65 return running_;
66 }
67
68 private:
71 bool locked_ = false;
72};
73
80
87
89 public:
92
93 ~GlobalSafepointInterruptTask() override = default;
96 delete;
97
98 private:
99 // v8::internal::CancelableTask overrides.
101
103};
104
106 Isolate* initiator, PerClientSafepointData* client_data) {
108 barrier_.Arm();
109
111 client_data->running());
112 client_data->set_locked();
113
114 if (isolate() != initiator) {
115 // An isolate might be waiting in the event loop. Post a task in order to
116 // wake it up.
118 std::make_unique<GlobalSafepointInterruptTask>(heap_));
119
120 // Request an interrupt in case of long-running code.
121 isolate()->stack_guard()->RequestGlobalSafepoint();
122 }
123}
124
126 Isolate* initiator) {
127 const bool is_initiator = isolate() == initiator;
128 return is_initiator ? IncludeMainThread::kNo : IncludeMainThread::kYes;
129}
130
132 IncludeMainThread include_main_thread,
133 IsolateSafepoint::RunningLocalHeaps& running_local_heaps) {
134 // There needs to be at least one LocalHeap for the main thread.
136
137 DCHECK(running_local_heaps.empty());
138
139 for (LocalHeap* local_heap = local_heaps_head_; local_heap;
140 local_heap = local_heap->next_) {
141 if (local_heap->is_main_thread() &&
142 include_main_thread == IncludeMainThread::kNo) {
143 continue;
144 }
145
146 const LocalHeap::ThreadState old_state =
147 local_heap->state_.SetSafepointRequested();
148
149 if (old_state.IsRunning()) {
150#if V8_OS_DARWIN
151 pthread_override_t qos_override = nullptr;
152
153 if (v8_flags.safepoint_bump_qos_class) {
154 // Bump the quality-of-service class to prevent priority inversion (high
155 // priority main thread blocking on lower priority background threads).
156 qos_override = pthread_override_qos_class_start_np(
157 local_heap->thread_handle(), QOS_CLASS_USER_INTERACTIVE, 0);
158 CHECK_NOT_NULL(qos_override);
159 }
160
161 running_local_heaps.emplace_back(local_heap, qos_override);
162#else
163 running_local_heaps.emplace_back(local_heap);
164#endif
165 }
167 local_heap->is_main_thread());
168 CHECK(!old_state.IsSafepointRequested());
169 }
170}
171
174 // Safepoints are only used for GCs, so GC requests should be ignored by
175 // default when parking for a safepoint.
176 IgnoreLocalGCRequests ignore_gc_requests(local_heap->heap());
177 local_heap->ExecuteWhileParked([this]() { local_heaps_mutex_.Lock(); });
178 }
179}
180
188
200
202 IncludeMainThread include_main_thread) {
203 for (LocalHeap* local_heap = local_heaps_head_; local_heap;
204 local_heap = local_heap->next_) {
205 if (local_heap->is_main_thread() &&
206 include_main_thread == IncludeMainThread::kNo) {
207 continue;
208 }
209
210 const LocalHeap::ThreadState old_state =
211 local_heap->state_.ClearSafepointRequested();
212
213 CHECK(old_state.IsParked());
214 CHECK(old_state.IsSafepointRequested());
216 local_heap->is_main_thread());
217 }
218}
219
221
223
225
230
232 base::MutexGuard guard(&mutex_);
233 DCHECK(!IsArmed());
234 armed_ = true;
235 stopped_ = 0;
236}
237
239 base::MutexGuard guard(&mutex_);
240 DCHECK(IsArmed());
241 armed_ = false;
242 stopped_ = 0;
243 cv_resume_.NotifyAll();
244}
245
247 const IsolateSafepoint::RunningLocalHeaps& running_local_heaps) {
248 base::MutexGuard guard(&mutex_);
249 DCHECK(IsArmed());
250 size_t running_count = running_local_heaps.size();
251 while (stopped_ < running_count) {
252 cv_stopped_.Wait(&mutex_);
253 }
254#if V8_OS_DARWIN
255 if (v8_flags.safepoint_bump_qos_class) {
256 for (auto& running_local_heap : running_local_heaps) {
257 CHECK_EQ(
258 pthread_override_qos_class_end_np(running_local_heap.qos_override),
259 0);
260 }
261 }
262#endif
263 DCHECK_EQ(stopped_, running_count);
264}
265
267 base::MutexGuard guard(&mutex_);
268 CHECK(IsArmed());
269 stopped_++;
270 cv_stopped_.NotifyOne();
271}
272
274 const auto scoped_blocking_call =
276 base::MutexGuard guard(&mutex_);
277 CHECK(IsArmed());
278 stopped_++;
279 cv_stopped_.NotifyOne();
280
281 while (IsArmed()) {
282 cv_resume_.Wait(&mutex_);
283 }
284}
285
287 const auto scoped_blocking_call =
289 base::MutexGuard guard(&mutex_);
290
291 while (IsArmed()) {
292 cv_resume_.Wait(&mutex_);
293 }
294}
295
297 AssertActive();
298 for (LocalHeap* current = local_heaps_head_; current;
299 current = current->next_) {
300 current->handles()->Iterate(visitor);
301 }
302}
303
308
310
314
319
323
325 : shared_space_isolate_(isolate) {}
326
343
363
367
369 // Safepoints need to be initiated on some main thread.
370 DCHECK_NULL(LocalHeap::Current());
371
372 if (!clients_mutex_.TryLock()) {
373 IgnoreLocalGCRequests ignore_gc_requests(initiator->heap());
375 [this]() { clients_mutex_.Lock(); });
376 }
377
378 if (++active_safepoint_scopes_ > 1) return;
379
381 initiator->counters()->gc_time_to_global_safepoint());
382 TRACE_GC(initiator->heap()->tracer(),
383 GCTracer::Scope::TIME_TO_GLOBAL_SAFEPOINT);
384
385 std::vector<PerClientSafepointData> clients;
386
387 // Try to initiate safepoint for all clients. Fail immediately when the
388 // local_heaps_mutex_ can't be locked without blocking.
389 IterateSharedSpaceAndClientIsolates([&clients, initiator](Isolate* client) {
390 clients.emplace_back(client);
392 initiator, &clients.back());
393 });
394
395 // Iterate all clients again to initiate the safepoint for all of them - even
396 // if that means blocking.
397 for (PerClientSafepointData& client : clients) {
398 if (client.is_locked()) continue;
399 client.safepoint()->InitiateGlobalSafepointScope(initiator, &client);
400 }
401
402#if DEBUG
403 for (const PerClientSafepointData& client : clients) {
405 }
406#endif // DEBUG
407
408 // Now that safepoints were initiated for all clients, wait until all threads
409 // of all clients reached a safepoint.
410 for (const PerClientSafepointData& client : clients) {
411 DCHECK(client.is_locked());
412 client.safepoint()->WaitUntilRunningThreadsInSafepoint(&client);
413 }
414}
415
419
420 if (--active_safepoint_scopes_ == 0) {
421 IterateSharedSpaceAndClientIsolates([initiator](Isolate* client) {
422 Heap* client_heap = client->heap();
423 client_heap->safepoint()->LeaveGlobalSafepointScope(initiator);
424 });
425 }
426
428}
429
431 if (!clients_mutex_.TryLock()) return true;
433 return false;
434}
435
437 : initiator_(initiator),
438 shared_space_isolate_(initiator->shared_space_isolate()) {
439 shared_space_isolate_->global_safepoint()->EnterGlobalSafepointScope(
440 initiator_);
441}
442
447
450 isolate_safepoint_.emplace(initiator->heap());
451 } else {
453 global_safepoint_.emplace(initiator);
454 }
455}
456
459 if (initiator->is_shared_space_isolate()) {
460 global_safepoint_.emplace(initiator);
461 } else {
462 isolate_safepoint_.emplace(initiator->heap());
463 }
464}
465
466} // namespace internal
467} // namespace v8
Builtins::Kind kind
Definition builtins.cc:40
virtual std::unique_ptr< ScopedBlockingCall > CreateBlockingScope(BlockingType blocking_type)
void PostTask(std::unique_ptr< Task > task, const SourceLocation &location=SourceLocation::Current())
Definition v8-platform.h:82
bool TryLock() V8_WARN_UNUSED_RESULT
Definition mutex.cc:39
V8_INLINE void AssertHeld() const
Definition mutex.h:153
size_t size() const
void emplace_back(Args &&... args)
Isolate * isolate() const
Definition factory.h:1281
GlobalSafepointInterruptTask & operator=(const GlobalSafepointInterruptTask &)=delete
GlobalSafepointInterruptTask(const GlobalSafepointInterruptTask &)=delete
V8_EXPORT_PRIVATE GlobalSafepointScope(Isolate *initiator)
Definition safepoint.cc:436
V8_EXPORT_PRIVATE ~GlobalSafepointScope()
Definition safepoint.cc:443
void IterateSharedSpaceAndClientIsolates(Callback callback)
Definition safepoint.h:200
void RemoveClient(Isolate *client)
Definition safepoint.cc:344
GlobalSafepoint(Isolate *isolate)
Definition safepoint.cc:324
base::RecursiveMutex clients_mutex_
Definition safepoint.h:218
void AppendClient(Isolate *client)
Definition safepoint.cc:327
V8_EXPORT_PRIVATE bool IsRequestedForTesting()
Definition safepoint.cc:430
void LeaveGlobalSafepointScope(Isolate *initiator)
Definition safepoint.cc:416
void EnterGlobalSafepointScope(Isolate *initiator)
Definition safepoint.cc:368
Isolate *const shared_space_isolate_
Definition safepoint.h:215
HeapState gc_state() const
Definition heap.h:521
LocalHeap * main_thread_local_heap()
Definition heap.h:842
std::shared_ptr< v8::TaskRunner > GetForegroundTaskRunner(TaskPriority priority=TaskPriority::kUserBlocking) const
Definition heap.cc:5903
IsolateSafepoint * safepoint()
Definition heap.h:579
GCTracer * tracer()
Definition heap.h:800
Isolate * isolate() const
Definition heap-inl.h:61
V8_EXPORT_PRIVATE ~IsolateSafepointScope()
Definition safepoint.cc:320
V8_EXPORT_PRIVATE IsolateSafepointScope(Heap *heap)
Definition safepoint.cc:315
void WaitUntilRunningThreadsInSafepoint(const IsolateSafepoint::RunningLocalHeaps &running_threads)
Definition safepoint.cc:246
Isolate * shared_space_isolate() const
Definition safepoint.cc:311
IncludeMainThread ShouldIncludeMainThread(Isolate *initiator)
Definition safepoint.cc:125
V8_EXPORT_PRIVATE void AssertMainThreadIsOnlyThread()
Definition safepoint.cc:304
void ClearSafepointRequestedFlags(IncludeMainThread include_main_thread)
Definition safepoint.cc:201
void InitiateGlobalSafepointScope(Isolate *initiator, PerClientSafepointData *client_data)
Definition safepoint.cc:74
void TryInitiateGlobalSafepointScope(Isolate *initiator, PerClientSafepointData *client_data)
Definition safepoint.cc:81
base::RecursiveMutex local_heaps_mutex_
Definition safepoint.h:158
void LeaveGlobalSafepointScope(Isolate *initiator)
Definition safepoint.cc:181
void InitiateGlobalSafepointScopeRaw(Isolate *initiator, PerClientSafepointData *client_data)
Definition safepoint.cc:105
void WaitUntilRunningThreadsInSafepoint(const PerClientSafepointData *client_data)
Definition safepoint.cc:226
void Iterate(RootVisitor *visitor)
Definition safepoint.cc:296
void SetSafepointRequestedFlags(IncludeMainThread include_main_thread, IsolateSafepoint::RunningLocalHeaps &running_local_heaps)
Definition safepoint.cc:131
void LockMutex(LocalHeap *local_heap)
Definition safepoint.cc:172
bool is_shared_space_isolate() const
Definition isolate.h:2292
Counters * counters()
Definition isolate.h:1180
GlobalSafepoint * global_safepoint() const
Definition isolate.h:2305
Isolate * global_safepoint_next_client_isolate_
Definition isolate.h:2889
StackGuard * stack_guard()
Definition isolate.h:1198
Isolate * shared_space_isolate() const
Definition isolate.h:2295
LocalHeap * main_thread_local_heap()
Definition isolate.cc:7479
Isolate * global_safepoint_prev_client_isolate_
Definition isolate.h:2888
constexpr bool IsRunning() const
Definition local-heap.h:252
constexpr bool IsCollectionRequested() const
Definition local-heap.h:268
constexpr bool IsParked() const
Definition local-heap.h:258
constexpr bool IsSafepointRequested() const
Definition local-heap.h:264
Heap * heap() const
Definition local-heap.h:122
V8_INLINE void ExecuteWhileParked(Callback callback)
IsolateSafepoint * safepoint() const
Definition safepoint.cc:57
IsolateSafepoint::RunningLocalHeaps running_
Definition safepoint.cc:70
IsolateSafepoint::RunningLocalHeaps & running()
Definition safepoint.cc:63
const IsolateSafepoint::RunningLocalHeaps & running() const
Definition safepoint.cc:64
PerClientSafepointData(Isolate *isolate)
Definition safepoint.cc:53
std::optional< IsolateSafepointScope > isolate_safepoint_
Definition safepoint.h:250
V8_EXPORT_PRIVATE SafepointScope(Isolate *initiator, SafepointKind kind)
Definition safepoint.cc:448
std::optional< GlobalSafepointScope > global_safepoint_
Definition safepoint.h:251
static ThreadId Current()
Definition thread-id.h:32
static V8_EXPORT_PRIVATE v8::Platform * GetCurrentPlatform()
Definition v8.cc:282
base::Mutex & mutex_
LineAndColumn current
#define TRACE_GC(tracer, scope_id)
Definition gc-tracer.h:35
V8_EXPORT_PRIVATE FlagValues v8_flags
#define DCHECK_NULL(val)
Definition logging.h:491
#define CHECK_IMPLIES(lhs, rhs)
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define CHECK_NOT_NULL(val)
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define DCHECK_GT(v1, v2)
Definition logging.h:487
Heap * heap_