Flutter Engine
The Flutter Engine
safepoint.h
Go to the documentation of this file.
1// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#ifndef RUNTIME_VM_HEAP_SAFEPOINT_H_
6#define RUNTIME_VM_HEAP_SAFEPOINT_H_
7
8#include "vm/globals.h"
9#include "vm/isolate.h"
10#include "vm/lockers.h"
11#include "vm/thread.h"
12#include "vm/thread_registry.h"
14
15namespace dart {
16
17// A stack based scope that can be used to perform an operation after getting
18// all threads to a safepoint. At the end of the operation all the threads are
19// resumed.
21 protected:
24
25 private:
26 SafepointLevel level_;
27
28 DISALLOW_COPY_AND_ASSIGN(SafepointOperationScope);
29};
30
31// Gets all mutators to a safepoint where GC is allowed.
33 public:
37
38 private:
39 DISALLOW_COPY_AND_ASSIGN(GcSafepointOperationScope);
40};
41
42// Gets all mutators to a safepoint where GC and Deopt is allowed.
44 public:
48
49 private:
50 DISALLOW_COPY_AND_ASSIGN(DeoptSafepointOperationScope);
51};
52
53// Gets all mutators to a safepoint where GC, Deopt and Reload is allowed.
55 public:
59
60 private:
61 DISALLOW_COPY_AND_ASSIGN(ReloadSafepointOperationScope);
62};
63
64// A stack based scope that can be used to perform an operation after getting
65// all threads to a safepoint. At the end of the operation all the threads are
66// resumed. Allocations in the scope will force heap growth.
68 public:
71
72 private:
73 SafepointLevel level_;
74 bool current_growth_controller_state_;
75
76 DISALLOW_COPY_AND_ASSIGN(ForceGrowthSafepointOperationScope);
77};
78
79// Implements handling of safepoint operations for all threads in an
80// IsolateGroup.
82 public:
85
89
90 // The innermost safepoint operation this thread owns
91 //
92 // Returns `SafepointLevel::kNone` if the current thread doesn't own any
93 // safepoint. Otherwise returns the innermost safepoint level of the current
94 // thread.
95 //
96 // * Will return SafepointLevel::kDeoptAndGC for
97 //
98 // DeoptSafepointOperationScope sp;
99 //
100 // * Will return SafepointLevel::kGC for
101 //
102 // DeoptSafepointOperationScope sp1;
103 // GcSafepointOperationScope sp2;
104 //
106 const Thread* current_thread) const;
107
109 for (intptr_t level = 0; level < SafepointLevel::kNumLevels; ++level) {
110 if (handlers_[level]->SafepointInProgress()) {
111 return true;
112 }
113 }
114 return false;
115 }
116
117 private:
118 class LevelHandler {
119 public:
120 LevelHandler(IsolateGroup* isolate_group, SafepointLevel level)
121 : isolate_group_(isolate_group), level_(level) {}
122
123 bool SafepointInProgress() const {
124 ASSERT(threads_lock()->IsOwnedByCurrentThread());
125 ASSERT((operation_count_ > 0) == (owner_ != nullptr));
126 return ((operation_count_ > 0) && (owner_ != nullptr));
127 }
128 void SetSafepointInProgress(Thread* T) {
129 ASSERT(threads_lock()->IsOwnedByCurrentThread());
130 ASSERT(owner_ == nullptr);
131 ASSERT(operation_count_ == 0);
132 operation_count_ = 1;
133 owner_ = T;
134 }
135 void ResetSafepointInProgress(Thread* T) {
136 ASSERT(threads_lock()->IsOwnedByCurrentThread());
137 ASSERT(owner_ == T);
138 ASSERT(operation_count_ == 1);
139 ASSERT(num_threads_not_parked_ == 0);
140 operation_count_ = 0;
141 owner_ = nullptr;
142 }
143 void NotifyWeAreParked(Thread* T);
144
145 IsolateGroup* isolate_group() const { return isolate_group_; }
146 Monitor* threads_lock() const {
147 return isolate_group_->thread_registry()->threads_lock();
148 }
149
150 private:
151 friend class SafepointHandler;
152
153 // Helper methods for [SafepointThreads]
154 void NotifyThreadsToGetToSafepointLevel(
155 Thread* T,
156 MallocGrowableArray<Dart_Port>* oob_isolates);
157 void WaitUntilThreadsReachedSafepointLevel();
158
159 // Helper methods for [ResumeThreads]
160 void NotifyThreadsToContinue(Thread* T);
161
162 IsolateGroup* isolate_group_;
163 SafepointLevel level_;
164
165 // Monitor used by thread initiating a safepoint operation to track threads
166 // not at a safepoint and wait for these threads to reach a safepoint.
167 Monitor parked_lock_;
168
169 // If a safepoint operation is currently in progress, this field contains
170 // the thread that initiated the safepoint operation, otherwise it is
171 // nullptr.
172 std::atomic<Thread*> owner_ = nullptr;
173
174 // The number of nested safepoint operations currently held.
175 std::atomic<int32_t> operation_count_ = 0;
176
177 // Count the number of threads the currently in-progress safepoint operation
178 // is waiting for to check-in.
179 int32_t num_threads_not_parked_ = 0;
180 };
181
182 void SafepointThreads(Thread* T, SafepointLevel level);
183 void ResumeThreads(Thread* T, SafepointLevel level);
184
185 // Helper methods for [SafepointThreads]
186 void AssertWeOwnLowerLevelSafepoints(Thread* T, SafepointLevel level);
187 void AssertWeDoNotOwnLowerLevelSafepoints(Thread* T, SafepointLevel level);
188 void AcquireLowerLevelSafepoints(Thread* T, SafepointLevel level);
189
190 // Helper methods for [ResumeThreads]
191 void ReleaseLowerLevelSafepoints(Thread* T, SafepointLevel level);
192
193 void EnterSafepointLocked(Thread* T, MonitorLocker* tl, SafepointLevel level);
194 void ExitSafepointLocked(Thread* T, MonitorLocker* tl, SafepointLevel level);
195
196 IsolateGroup* isolate_group() const { return isolate_group_; }
197 Monitor* threads_lock() const {
198 return isolate_group_->thread_registry()->threads_lock();
199 }
200
201 IsolateGroup* isolate_group_;
202
203 LevelHandler* handlers_[SafepointLevel::kNumLevels];
204
205 friend class Isolate;
206 friend class IsolateGroup;
209 friend class HeapIterationScope;
210};
211
212/*
213 * Set of StackResource classes to track thread execution state transitions:
214 *
215 * kThreadInGenerated transitioning to
216 * ==> kThreadInVM:
217 * - set_execution_state(kThreadInVM).
218 * - block if safepoint is requested.
219 * ==> kThreadInNative:
220 * - set_execution_state(kThreadInNative).
221 * - EnterSafepoint().
222 * ==> kThreadInBlockedState:
223 * - Invalid transition
224 *
225 * kThreadInVM transitioning to
226 * ==> kThreadInGenerated
227 * - set_execution_state(kThreadInGenerated).
228 * ==> kThreadInNative
229 * - set_execution_state(kThreadInNative).
230 * - EnterSafepoint.
231 * ==> kThreadInBlockedState
232 * - set_execution_state(kThreadInBlockedState).
233 * - EnterSafepoint.
234 *
235 * kThreadInNative transitioning to
236 * ==> kThreadInGenerated
237 * - ExitSafepoint.
238 * - set_execution_state(kThreadInGenerated).
239 * ==> kThreadInVM
240 * - ExitSafepoint.
241 * - set_execution_state(kThreadInVM).
242 * ==> kThreadInBlocked
243 * - Invalid transition.
244 *
245 * kThreadInBlocked transitioning to
246 * ==> kThreadInVM
247 * - ExitSafepoint.
248 * - set_execution_state(kThreadInVM).
249 * ==> kThreadInNative
250 * - Invalid transition.
251 * ==> kThreadInGenerated
252 * - Invalid transition.
253 */
255 public:
258
260 ASSERT(thread()->isolate() != nullptr);
261 ASSERT(thread()->isolate()->safepoint_handler() != nullptr);
262 return thread()->isolate()->safepoint_handler();
263 }
264
265 private:
266 DISALLOW_COPY_AND_ASSIGN(TransitionSafepointState);
267};
268
269// TransitionGeneratedToVM is used to transition the safepoint state of a
270// thread from "running generated code" to "running vm code" and ensures
271// that the state is reverted back to "running generated code" when
272// exiting the scope/frame.
274 public:
277 ASSERT(T->execution_state() == Thread::kThreadInGenerated);
278 T->set_execution_state(Thread::kThreadInVM);
279 // Fast check to see if a safepoint is requested or not.
280 // We do the more expensive operation of blocking the thread
281 // only if a safepoint is requested.
282 if (T->IsSafepointRequested()) {
283 T->BlockForSafepoint();
284 }
285 }
286
288 ASSERT(thread()->execution_state() == Thread::kThreadInVM);
290 }
291
292 private:
293 DISALLOW_COPY_AND_ASSIGN(TransitionGeneratedToVM);
294};
295
296// TransitionGeneratedToNative is used to transition the safepoint state of a
297// thread from "running generated code" to "running native code" and ensures
298// that the state is reverted back to "running generated code" when
299// exiting the scope/frame.
301 public:
304 // Native code is considered to be at a safepoint and so we mark it
305 // accordingly.
306 ASSERT(T->execution_state() == Thread::kThreadInGenerated);
307 T->set_execution_state(Thread::kThreadInNative);
308 T->EnterSafepoint();
309 }
310
312 // We are returning to generated code and so we are not at a safepoint
313 // anymore.
314 ASSERT(thread()->execution_state() == Thread::kThreadInNative);
317 }
318
319 private:
320 DISALLOW_COPY_AND_ASSIGN(TransitionGeneratedToNative);
321};
322
323// TransitionVMToBlocked is used to transition the safepoint state of a
324// thread from "running vm code" to "blocked on a monitor" and ensures
325// that the state is reverted back to "running vm code" when
326// exiting the scope/frame.
328 public:
330 ASSERT(T->CanAcquireSafepointLocks());
331 // A thread blocked on a monitor is considered to be at a safepoint.
332 ASSERT(T->execution_state() == Thread::kThreadInVM);
333 T->set_execution_state(Thread::kThreadInBlockedState);
334 T->EnterSafepoint();
335 }
336
338 // We are returning to vm code and so we are not at a safepoint anymore.
339 ASSERT(thread()->execution_state() == Thread::kThreadInBlockedState);
342 }
343
344 private:
345 DISALLOW_COPY_AND_ASSIGN(TransitionVMToBlocked);
346};
347
348// TransitionVMToNative is used to transition the safepoint state of a
349// thread from "running vm code" to "running native code" and ensures
350// that the state is reverted back to "running vm code" when
351// exiting the scope/frame.
353 public:
355 // A thread running native code is considered to be at a safepoint.
356 ASSERT(T->execution_state() == Thread::kThreadInVM);
357 T->set_execution_state(Thread::kThreadInNative);
358 T->EnterSafepoint();
359 }
360
362 // We are returning to vm code and so we are not at a safepoint anymore.
363 ASSERT(thread()->execution_state() == Thread::kThreadInNative);
366 }
367
368 private:
369 DISALLOW_COPY_AND_ASSIGN(TransitionVMToNative);
370};
371
372// TransitionVMToGenerated is used to transition the safepoint state of a
373// thread from "running vm code" to "running generated code" and ensures
374// that the state is reverted back to "running vm code" when
375// exiting the scope/frame.
377 public:
380 ASSERT(T->execution_state() == Thread::kThreadInVM);
381 T->set_execution_state(Thread::kThreadInGenerated);
382 }
383
385 ASSERT(thread()->execution_state() == Thread::kThreadInGenerated);
387 // Fast check to see if a safepoint is requested or not.
388 if (thread()->IsSafepointRequested()) {
390 }
391 }
392
393 private:
394 DISALLOW_COPY_AND_ASSIGN(TransitionVMToGenerated);
395};
396
397// TransitionNativeToVM is used to transition the safepoint state of a
398// thread from "running native code" to "running vm code" and ensures
399// that the state is reverted back to "running native code" when
400// exiting the scope/frame.
402 public:
404 // We are about to execute vm code and so we are not at a safepoint anymore.
405 ASSERT(T->execution_state() == Thread::kThreadInNative);
406 if (T->no_callback_scope_depth() == 0) {
407 T->ExitSafepoint();
408 }
409 T->set_execution_state(Thread::kThreadInVM);
410 }
411
413 // We are returning to native code and so we are at a safepoint.
414 ASSERT(thread()->execution_state() == Thread::kThreadInVM);
416 if (thread()->no_callback_scope_depth() == 0) {
418 }
419 }
420
421 private:
422 DISALLOW_COPY_AND_ASSIGN(TransitionNativeToVM);
423};
424
425// TransitionToGenerated is used to transition the safepoint state of a
426// thread from "running vm code" or "running native code" to
427// "running generated code" and ensures that the state is reverted back
428// to "running vm code" or "running native code" when exiting the
429// scope/frame.
431 public:
433 : TransitionSafepointState(T), execution_state_(T->execution_state()) {
435 ASSERT((execution_state_ == Thread::kThreadInVM) ||
436 (execution_state_ == Thread::kThreadInNative));
437 if (execution_state_ == Thread::kThreadInNative) {
438 T->ExitSafepoint();
439 }
440 T->set_execution_state(Thread::kThreadInGenerated);
441 }
442
444 ASSERT(thread()->execution_state() == Thread::kThreadInGenerated);
445 if (execution_state_ == Thread::kThreadInNative) {
448 } else {
449 ASSERT(execution_state_ == Thread::kThreadInVM);
451 }
452 }
453
454 private:
455 uint32_t execution_state_;
456 DISALLOW_COPY_AND_ASSIGN(TransitionToGenerated);
457};
458
459// TransitionToVM is used to transition the safepoint state of a
460// thread from "running native code" to "running vm code"
461// and ensures that the state is reverted back to "running native code"
462// when exiting the scope/frame.
463// This transition helper is mainly used in the error path of the
464// Dart API implementations where we sometimes do not have an explicit
465// transition set up.
467 public:
469 : TransitionSafepointState(T), execution_state_(T->execution_state()) {
471 ASSERT((execution_state_ == Thread::kThreadInVM) ||
472 (execution_state_ == Thread::kThreadInNative));
473 if (execution_state_ == Thread::kThreadInNative) {
474 T->ExitSafepoint();
475 T->set_execution_state(Thread::kThreadInVM);
476 }
477 ASSERT(T->execution_state() == Thread::kThreadInVM);
478 }
479
481 ASSERT(thread()->execution_state() == Thread::kThreadInVM);
482 if (execution_state_ == Thread::kThreadInNative) {
485 }
486 }
487
488 private:
489 uint32_t execution_state_;
490 DISALLOW_COPY_AND_ASSIGN(TransitionToVM);
491};
492
493// TransitionToNative is used to transition the safepoint state of a
494// thread from "running VM code" to "running native code"
495// and ensures that the state is reverted back to the initial state
496// when exiting the scope/frame.
498 public:
500 : TransitionSafepointState(T), execution_state_(T->execution_state()) {
502 ASSERT((execution_state_ == Thread::kThreadInVM) ||
503 (execution_state_ == Thread::kThreadInNative));
504 if (execution_state_ == Thread::kThreadInVM) {
505 T->set_execution_state(Thread::kThreadInNative);
506 T->EnterSafepoint();
507 }
508 ASSERT(T->execution_state() == Thread::kThreadInNative);
509 }
510
512 ASSERT(thread()->execution_state() == Thread::kThreadInNative);
513 if (execution_state_ == Thread::kThreadInVM) {
516 }
517 }
518
519 private:
520 uint32_t execution_state_;
521 DISALLOW_COPY_AND_ASSIGN(TransitionToNative);
522};
523
524} // namespace dart
525
526#endif // RUNTIME_VM_HEAP_SAFEPOINT_H_
ForceGrowthSafepointOperationScope(Thread *T, SafepointLevel level)
Definition: safepoint.cc:32
GcSafepointOperationScope(Thread *T)
Definition: safepoint.h:34
ThreadRegistry * thread_registry() const
Definition: isolate.h:333
SafepointHandler * safepoint_handler() const
Definition: isolate.h:996
SafepointLevel InnermostSafepointOperation(const Thread *current_thread) const
Definition: safepoint.cc:291
bool AnySafepointInProgressLocked()
Definition: safepoint.h:108
SafepointHandler(IsolateGroup *I)
Definition: safepoint.cc:62
void EnterSafepointUsingLock(Thread *T)
Definition: safepoint.cc:279
void BlockForSafepoint(Thread *T)
Definition: safepoint.cc:324
friend class IsolateGroup
Definition: safepoint.h:206
void ExitSafepointUsingLock(Thread *T)
Definition: safepoint.cc:284
SafepointOperationScope(Thread *T, SafepointLevel level)
Definition: safepoint.cc:15
Monitor * threads_lock() const
void set_execution_state(ExecutionState state)
Definition: thread.h:1048
static Thread * Current()
Definition: thread.h:362
void ExitSafepoint()
Definition: thread.h:1094
void EnterSafepoint()
Definition: thread.h:1076
Isolate * isolate() const
Definition: thread.h:534
@ kThreadInNative
Definition: thread.h:1036
@ kThreadInBlockedState
Definition: thread.h:1037
@ kThreadInGenerated
Definition: thread.h:1035
void BlockForSafepoint()
Definition: thread.cc:1348
TransitionGeneratedToVM(Thread *T)
Definition: safepoint.h:275
TransitionNativeToVM(Thread *T)
Definition: safepoint.h:403
SafepointHandler * handler() const
Definition: safepoint.h:259
TransitionToGenerated(Thread *T)
Definition: safepoint.h:432
TransitionToNative(Thread *T)
Definition: safepoint.h:499
TransitionToVM(Thread *T)
Definition: safepoint.h:468
TransitionVMToBlocked(Thread *T)
Definition: safepoint.h:329
TransitionVMToGenerated(Thread *T)
Definition: safepoint.h:378
TransitionVMToNative(Thread *T)
Definition: safepoint.h:354
#define ASSERT(E)
Definition: dart_vm.cc:33
SafepointLevel
Definition: thread.h:289
@ kGC
Definition: thread.h:291
@ kNumLevels
Definition: thread.h:297
@ kGCAndDeoptAndReload
Definition: thread.h:295
@ kGCAndDeopt
Definition: thread.h:293
#define T
Definition: precompiler.cc:65
Definition: SkMD5.cpp:134