OLD | NEW |
---|---|
(Empty) | |
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 VM_SAFEPOINT_H_ | |
6 #define VM_SAFEPOINT_H_ | |
7 | |
8 #include "vm/globals.h" | |
9 #include "vm/lockers.h" | |
10 #include "vm/thread.h" | |
11 | |
12 namespace dart { | |
13 | |
14 // A stack based scope that can be used to perform an operation after getting | |
15 // all threads to a safepoint. At the end of the operation all the threads are | |
16 // resumed. | |
17 class SafepointOperationScope : public StackResource { | |
18 public: | |
19 explicit SafepointOperationScope(Thread* T); | |
20 ~SafepointOperationScope(); | |
21 | |
22 private: | |
23 DISALLOW_COPY_AND_ASSIGN(SafepointOperationScope); | |
24 }; | |
25 | |
26 | |
27 // Implements handling of safepoint operations for all threads in an Isolate. | |
28 class SafepointHandler { | |
29 public: | |
30 explicit SafepointHandler(Isolate* I); | |
31 ~SafepointHandler(); | |
32 | |
33 void EnterSafepointUsingLock(Thread* T); | |
34 void ExitSafepointUsingLock(Thread* T); | |
35 | |
36 void SafepointThreads(Thread* T); | |
37 void ResumeThreads(Thread* T); | |
38 | |
39 void BlockForSafepoint(Thread* T); | |
40 | |
41 private: | |
42 Isolate* isolate() const { return isolate_; } | |
43 Monitor* threads_lock() const { return isolate_->threads_lock(); } | |
44 bool safepoint_in_progress() const { | |
45 ASSERT(threads_lock()->IsOwnedByCurrentThread()); | |
46 return safepoint_in_progress_; | |
47 } | |
48 void set_safepoint_in_progress(bool value) { | |
49 ASSERT(threads_lock()->IsOwnedByCurrentThread()); | |
50 safepoint_in_progress_ = value; | |
51 } | |
52 | |
53 Isolate* isolate_; | |
54 | |
55 // Monitor used by thread initiating a safepoint operation to track threads | |
56 // not at a safepoint and wait for these threads to reach a safepoint. | |
57 Monitor* safepoint_lock_; | |
58 int32_t number_threads_not_at_safepoint_; | |
59 | |
60 // Flag to indicate if a safepoint operation is currently in progress. | |
61 bool safepoint_in_progress_; | |
62 | |
63 friend class Isolate; | |
64 friend class SafepointOperationScope; | |
65 }; | |
66 | |
67 | |
68 /* | |
69 * Set of StackResource classes to track thread execution state transitions: | |
70 * | |
71 * kThreadInGenerated transitioning to | |
72 * ==> kThreadInVM: | |
73 * - set_execution_state(kThreadInVM). | |
74 * - block if safepoint is requested. | |
75 * ==> kThreadInNative: | |
76 * - set_execution_state(kThreadInNative). | |
77 * - EnterSafepoint(). | |
78 * ==> kThreadInBlockedState: | |
79 * - Invalid transition | |
80 * | |
81 * kThreadInVM transitioning to | |
82 * ==> kThreadInGenerated | |
83 * - set_execution_state(kThreadInGenerated). | |
84 * ==> kThreadInNative | |
85 * - set_execution_state(kThreadInNative). | |
86 * - EnterSafepoint. | |
87 * ==> kThreadInBlockedState | |
88 * - set_execution_state(kThreadInBlockedState). | |
89 * - EnterSafepoint. | |
90 * | |
91 * kThreadInNative transitioning to | |
92 * ==> kThreadInGenerated | |
93 * - ExitSafepoint. | |
94 * - set_execution_state(kThreadInGenerated). | |
95 * ==> kThreadInVM | |
96 * - ExitSafepoint. | |
97 * - set_execution_state(kThreadInVM). | |
98 * ==> kThreadInBlocked | |
99 * - Invalid transition. | |
100 * | |
101 * kThreadInBlocked transitioning to | |
102 * ==> kThreadInVM | |
103 * - ExitSafepoint. | |
104 * - set_execution_state(kThreadInVM). | |
105 * ==> kThreadInNative | |
106 * - Invalid transition. | |
107 * ==> kThreadInGenerated | |
108 * - Invalid transition. | |
109 */ | |
110 class TransitionSafepointState : public StackResource { | |
111 public: | |
112 explicit TransitionSafepointState(Thread* T) : StackResource(T) {} | |
113 ~TransitionSafepointState() {} | |
zra
2016/01/13 22:16:13
Does this destructor need to be virtual?
siva
2016/01/27 19:07:50
There are no virtual methods in any of the subclas
| |
114 | |
115 SafepointHandler* handler() const { | |
116 ASSERT(thread()->isolate() != NULL); | |
117 ASSERT(thread()->isolate()->safepoint_handler() != NULL); | |
118 return thread()->isolate()->safepoint_handler(); | |
119 } | |
120 | |
121 private: | |
122 DISALLOW_COPY_AND_ASSIGN(TransitionSafepointState); | |
123 }; | |
124 | |
125 | |
126 // TransitionGeneratedToVM is used to transition the safepoint state of a | |
127 // thread from "running generated code" to "running vm code" and ensures | |
128 // that the state is reverted back to "running generated code" when | |
129 // exiting the scope/frame. | |
130 class TransitionGeneratedToVM : public TransitionSafepointState { | |
131 public: | |
132 explicit TransitionGeneratedToVM(Thread* T) : TransitionSafepointState(T) { | |
133 ASSERT(T == Thread::Current()); | |
134 ASSERT(T->execution_state() == Thread::kThreadInGenerated); | |
135 T->set_execution_state(Thread::kThreadInVM); | |
136 // Fast check to see if a safepoint is requested or not. | |
137 // We do the more expensive operation of blocking the thread | |
138 // only if a safepoint is requested. | |
139 if (T->IsSafepointRequested()) { | |
140 handler()->BlockForSafepoint(T); | |
141 } | |
142 } | |
143 | |
144 ~TransitionGeneratedToVM() { | |
145 ASSERT(thread()->execution_state() == Thread::kThreadInVM); | |
146 thread()->set_execution_state(Thread::kThreadInGenerated); | |
147 } | |
148 | |
149 private: | |
150 DISALLOW_COPY_AND_ASSIGN(TransitionGeneratedToVM); | |
151 }; | |
152 | |
153 | |
154 // TransitionGeneratedToNative is used to transition the safepoint state of a | |
155 // thread from "running generated code" to "running native code" and ensures | |
156 // that the state is reverted back to "running generated code" when | |
157 // exiting the scope/frame. | |
158 class TransitionGeneratedToNative : public TransitionSafepointState { | |
159 public: | |
160 explicit TransitionGeneratedToNative(Thread* T) | |
161 : TransitionSafepointState(T) { | |
162 // Native code is considered to be at a safepoint and so we mark it | |
163 // accordingly. | |
164 ASSERT(T->execution_state() == Thread::kThreadInGenerated); | |
165 T->set_execution_state(Thread::kThreadInNative); | |
166 T->EnterSafepoint(); | |
167 } | |
168 | |
169 ~TransitionGeneratedToNative() { | |
170 // We are returning to generated code and so we are not at a safepoint | |
171 // anymore. | |
172 ASSERT(thread()->execution_state() == Thread::kThreadInNative); | |
173 thread()->ExitSafepoint(); | |
174 thread()->set_execution_state(Thread::kThreadInGenerated); | |
175 } | |
176 | |
177 private: | |
178 DISALLOW_COPY_AND_ASSIGN(TransitionGeneratedToNative); | |
179 }; | |
180 | |
181 | |
182 // TransitionVMToBlocked is used to transition the safepoint state of a | |
183 // thread from "running vm code" to "blocked on a monitor" and ensures | |
184 // that the state is reverted back to "running vm code" when | |
185 // exiting the scope/frame. | |
186 class TransitionVMToBlocked : public TransitionSafepointState { | |
187 public: | |
188 explicit TransitionVMToBlocked(Thread* T) : TransitionSafepointState(T) { | |
189 // A thread blocked on a monitor is considered to be at a safepoint. | |
190 ASSERT(T->execution_state() == Thread::kThreadInVM); | |
191 T->set_execution_state(Thread::kThreadInBlockedState); | |
192 T->EnterSafepoint(); | |
193 } | |
194 | |
195 ~TransitionVMToBlocked() { | |
196 // We are returning to vm code and so we are not at a safepoint anymore. | |
197 ASSERT(thread()->execution_state() == Thread::kThreadInBlockedState); | |
198 thread()->ExitSafepoint(); | |
199 thread()->set_execution_state(Thread::kThreadInVM); | |
200 } | |
201 | |
202 private: | |
203 DISALLOW_COPY_AND_ASSIGN(TransitionVMToBlocked); | |
204 }; | |
205 | |
206 | |
207 // TransitionVMToNative is used to transition the safepoint state of a | |
208 // thread from "running vm code" to "running native code" and ensures | |
209 // that the state is reverted back to "running vm code" when | |
210 // exiting the scope/frame. | |
211 class TransitionVMToNative : public TransitionSafepointState { | |
212 public: | |
213 explicit TransitionVMToNative(Thread* T) : TransitionSafepointState(T) { | |
214 // A thread running native code is considered to be at a safepoint. | |
215 ASSERT(T->execution_state() == Thread::kThreadInVM); | |
216 T->set_execution_state(Thread::kThreadInNative); | |
217 T->EnterSafepoint(); | |
218 } | |
219 | |
220 ~TransitionVMToNative() { | |
221 // We are returning to vm code and so we are not at a safepoint anymore. | |
222 ASSERT(thread()->execution_state() == Thread::kThreadInNative); | |
223 thread()->ExitSafepoint(); | |
224 thread()->set_execution_state(Thread::kThreadInVM); | |
225 } | |
226 | |
227 private: | |
228 DISALLOW_COPY_AND_ASSIGN(TransitionVMToNative); | |
229 }; | |
230 | |
231 | |
232 // TransitionVMToGenerated is used to transition the safepoint state of a | |
233 // thread from "running vm code" to "running generated code" and ensures | |
234 // that the state is reverted back to "running vm code" when | |
235 // exiting the scope/frame. | |
236 class TransitionVMToGenerated : public TransitionSafepointState { | |
237 public: | |
238 explicit TransitionVMToGenerated(Thread* T) : TransitionSafepointState(T) { | |
239 ASSERT(T == Thread::Current()); | |
240 ASSERT(T->execution_state() == Thread::kThreadInVM); | |
241 T->set_execution_state(Thread::kThreadInGenerated); | |
242 } | |
243 | |
244 ~TransitionVMToGenerated() { | |
245 ASSERT(thread()->execution_state() == Thread::kThreadInGenerated); | |
246 thread()->set_execution_state(Thread::kThreadInVM); | |
247 // Fast check to see if a safepoint is requested or not. | |
248 // We do the more expensive operation of blocking the thread | |
249 // only if a safepoint is requested. | |
250 if (thread()->IsSafepointRequested()) { | |
251 handler()->BlockForSafepoint(thread()); | |
252 } | |
253 } | |
254 | |
255 private: | |
256 DISALLOW_COPY_AND_ASSIGN(TransitionVMToGenerated); | |
257 }; | |
258 | |
259 | |
260 // TransitionNativeToVM is used to transition the safepoint state of a | |
261 // thread from "running native code" to "running vm code" and ensures | |
262 // that the state is reverted back to "running native code" when | |
263 // exiting the scope/frame. | |
264 class TransitionNativeToVM : public TransitionSafepointState { | |
265 public: | |
266 explicit TransitionNativeToVM(Thread* T) : TransitionSafepointState(T) { | |
267 // We are about to execute vm code and so we are not at a safepoint anymore. | |
268 ASSERT(T->execution_state() == Thread::kThreadInNative); | |
269 T->ExitSafepoint(); | |
270 T->set_execution_state(Thread::kThreadInVM); | |
271 } | |
272 | |
273 ~TransitionNativeToVM() { | |
274 // We are returning to native code and so we are at a safepoint. | |
275 ASSERT(thread()->execution_state() == Thread::kThreadInVM); | |
276 thread()->set_execution_state(Thread::kThreadInNative); | |
277 thread()->EnterSafepoint(); | |
278 } | |
279 | |
280 private: | |
281 DISALLOW_COPY_AND_ASSIGN(TransitionNativeToVM); | |
282 }; | |
283 | |
284 | |
285 // TransitionToGenerated is used to transition the safepoint state of a | |
286 // thread from "running vm code" or "running native code" to | |
287 // "running generated code" and ensures that the state is reverted back | |
288 // to "running vm code" or "running native code" when exiting the | |
289 // scope/frame. | |
290 class TransitionToGenerated : public TransitionSafepointState { | |
291 public: | |
292 explicit TransitionToGenerated(Thread* T) | |
293 : TransitionSafepointState(T), | |
294 execution_state_(T->execution_state()) { | |
295 ASSERT(T == Thread::Current()); | |
296 ASSERT((execution_state_ == Thread::kThreadInVM) || | |
297 (execution_state_ == Thread::kThreadInNative)); | |
298 if (execution_state_ == Thread::kThreadInNative) { | |
299 T->ExitSafepoint(); | |
300 } | |
301 T->set_execution_state(Thread::kThreadInGenerated); | |
302 } | |
303 | |
304 ~TransitionToGenerated() { | |
305 ASSERT(thread()->execution_state() == Thread::kThreadInGenerated); | |
306 if (execution_state_ == Thread::kThreadInNative) { | |
307 thread()->set_execution_state(Thread::kThreadInNative); | |
308 thread()->EnterSafepoint(); | |
309 } else { | |
310 ASSERT(execution_state_ == Thread::kThreadInVM); | |
311 thread()->set_execution_state(Thread::kThreadInVM); | |
312 // Fast check to see if a safepoint is requested or not. | |
313 // We do the more expensive operation of blocking the thread | |
314 // only if a safepoint is requested. | |
315 if (thread()->IsSafepointRequested()) { | |
316 handler()->BlockForSafepoint(thread()); | |
317 } | |
318 } | |
319 } | |
320 | |
321 private: | |
322 int16_t execution_state_; | |
323 DISALLOW_COPY_AND_ASSIGN(TransitionToGenerated); | |
324 }; | |
325 | |
326 } // namespace dart | |
327 | |
328 #endif // VM_SAFEPOINT_H_ | |
OLD | NEW |