| OLD | NEW |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef RUNTIME_VM_SAFEPOINT_H_ | 5 #ifndef RUNTIME_VM_SAFEPOINT_H_ |
| 6 #define RUNTIME_VM_SAFEPOINT_H_ | 6 #define RUNTIME_VM_SAFEPOINT_H_ |
| 7 | 7 |
| 8 #include "vm/globals.h" | 8 #include "vm/globals.h" |
| 9 #include "vm/lockers.h" | 9 #include "vm/lockers.h" |
| 10 #include "vm/thread.h" | 10 #include "vm/thread.h" |
| 11 | 11 |
| 12 namespace dart { | 12 namespace dart { |
| 13 | 13 |
| 14 // A stack based scope that can be used to perform an operation after getting | 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 | 15 // all threads to a safepoint. At the end of the operation all the threads are |
| 16 // resumed. | 16 // resumed. |
| 17 class SafepointOperationScope : public StackResource { | 17 class SafepointOperationScope : public StackResource { |
| 18 public: | 18 public: |
| 19 explicit SafepointOperationScope(Thread* T); | 19 explicit SafepointOperationScope(Thread* T); |
| 20 ~SafepointOperationScope(); | 20 ~SafepointOperationScope(); |
| 21 | 21 |
| 22 private: | 22 private: |
| 23 DISALLOW_COPY_AND_ASSIGN(SafepointOperationScope); | 23 DISALLOW_COPY_AND_ASSIGN(SafepointOperationScope); |
| 24 }; | 24 }; |
| 25 | 25 |
| 26 | |
| 27 // Implements handling of safepoint operations for all threads in an Isolate. | 26 // Implements handling of safepoint operations for all threads in an Isolate. |
| 28 class SafepointHandler { | 27 class SafepointHandler { |
| 29 public: | 28 public: |
| 30 explicit SafepointHandler(Isolate* I); | 29 explicit SafepointHandler(Isolate* I); |
| 31 ~SafepointHandler(); | 30 ~SafepointHandler(); |
| 32 | 31 |
| 33 void EnterSafepointUsingLock(Thread* T); | 32 void EnterSafepointUsingLock(Thread* T); |
| 34 void ExitSafepointUsingLock(Thread* T); | 33 void ExitSafepointUsingLock(Thread* T); |
| 35 | 34 |
| 36 void BlockForSafepoint(Thread* T); | 35 void BlockForSafepoint(Thread* T); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 87 int32_t safepoint_operation_count_; | 86 int32_t safepoint_operation_count_; |
| 88 | 87 |
| 89 // If a safepoint operation is currently in progress, this field contains | 88 // If a safepoint operation is currently in progress, this field contains |
| 90 // the thread that initiated the safepoint operation, otherwise it is NULL. | 89 // the thread that initiated the safepoint operation, otherwise it is NULL. |
| 91 Thread* owner_; | 90 Thread* owner_; |
| 92 | 91 |
| 93 friend class Isolate; | 92 friend class Isolate; |
| 94 friend class SafepointOperationScope; | 93 friend class SafepointOperationScope; |
| 95 }; | 94 }; |
| 96 | 95 |
| 97 | |
| 98 /* | 96 /* |
| 99 * Set of StackResource classes to track thread execution state transitions: | 97 * Set of StackResource classes to track thread execution state transitions: |
| 100 * | 98 * |
| 101 * kThreadInGenerated transitioning to | 99 * kThreadInGenerated transitioning to |
| 102 * ==> kThreadInVM: | 100 * ==> kThreadInVM: |
| 103 * - set_execution_state(kThreadInVM). | 101 * - set_execution_state(kThreadInVM). |
| 104 * - block if safepoint is requested. | 102 * - block if safepoint is requested. |
| 105 * ==> kThreadInNative: | 103 * ==> kThreadInNative: |
| 106 * - set_execution_state(kThreadInNative). | 104 * - set_execution_state(kThreadInNative). |
| 107 * - EnterSafepoint(). | 105 * - EnterSafepoint(). |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 145 SafepointHandler* handler() const { | 143 SafepointHandler* handler() const { |
| 146 ASSERT(thread()->isolate() != NULL); | 144 ASSERT(thread()->isolate() != NULL); |
| 147 ASSERT(thread()->isolate()->safepoint_handler() != NULL); | 145 ASSERT(thread()->isolate()->safepoint_handler() != NULL); |
| 148 return thread()->isolate()->safepoint_handler(); | 146 return thread()->isolate()->safepoint_handler(); |
| 149 } | 147 } |
| 150 | 148 |
| 151 private: | 149 private: |
| 152 DISALLOW_COPY_AND_ASSIGN(TransitionSafepointState); | 150 DISALLOW_COPY_AND_ASSIGN(TransitionSafepointState); |
| 153 }; | 151 }; |
| 154 | 152 |
| 155 | |
| 156 // TransitionGeneratedToVM is used to transition the safepoint state of a | 153 // TransitionGeneratedToVM is used to transition the safepoint state of a |
| 157 // thread from "running generated code" to "running vm code" and ensures | 154 // thread from "running generated code" to "running vm code" and ensures |
| 158 // that the state is reverted back to "running generated code" when | 155 // that the state is reverted back to "running generated code" when |
| 159 // exiting the scope/frame. | 156 // exiting the scope/frame. |
| 160 class TransitionGeneratedToVM : public TransitionSafepointState { | 157 class TransitionGeneratedToVM : public TransitionSafepointState { |
| 161 public: | 158 public: |
| 162 explicit TransitionGeneratedToVM(Thread* T) : TransitionSafepointState(T) { | 159 explicit TransitionGeneratedToVM(Thread* T) : TransitionSafepointState(T) { |
| 163 ASSERT(T == Thread::Current()); | 160 ASSERT(T == Thread::Current()); |
| 164 ASSERT(T->execution_state() == Thread::kThreadInGenerated); | 161 ASSERT(T->execution_state() == Thread::kThreadInGenerated); |
| 165 T->set_execution_state(Thread::kThreadInVM); | 162 T->set_execution_state(Thread::kThreadInVM); |
| 166 // Fast check to see if a safepoint is requested or not. | 163 // Fast check to see if a safepoint is requested or not. |
| 167 // We do the more expensive operation of blocking the thread | 164 // We do the more expensive operation of blocking the thread |
| 168 // only if a safepoint is requested. | 165 // only if a safepoint is requested. |
| 169 if (T->IsSafepointRequested()) { | 166 if (T->IsSafepointRequested()) { |
| 170 handler()->BlockForSafepoint(T); | 167 handler()->BlockForSafepoint(T); |
| 171 } | 168 } |
| 172 } | 169 } |
| 173 | 170 |
| 174 ~TransitionGeneratedToVM() { | 171 ~TransitionGeneratedToVM() { |
| 175 ASSERT(thread()->execution_state() == Thread::kThreadInVM); | 172 ASSERT(thread()->execution_state() == Thread::kThreadInVM); |
| 176 thread()->set_execution_state(Thread::kThreadInGenerated); | 173 thread()->set_execution_state(Thread::kThreadInGenerated); |
| 177 } | 174 } |
| 178 | 175 |
| 179 private: | 176 private: |
| 180 DISALLOW_COPY_AND_ASSIGN(TransitionGeneratedToVM); | 177 DISALLOW_COPY_AND_ASSIGN(TransitionGeneratedToVM); |
| 181 }; | 178 }; |
| 182 | 179 |
| 183 | |
| 184 // TransitionGeneratedToNative is used to transition the safepoint state of a | 180 // TransitionGeneratedToNative is used to transition the safepoint state of a |
| 185 // thread from "running generated code" to "running native code" and ensures | 181 // thread from "running generated code" to "running native code" and ensures |
| 186 // that the state is reverted back to "running generated code" when | 182 // that the state is reverted back to "running generated code" when |
| 187 // exiting the scope/frame. | 183 // exiting the scope/frame. |
| 188 class TransitionGeneratedToNative : public TransitionSafepointState { | 184 class TransitionGeneratedToNative : public TransitionSafepointState { |
| 189 public: | 185 public: |
| 190 explicit TransitionGeneratedToNative(Thread* T) | 186 explicit TransitionGeneratedToNative(Thread* T) |
| 191 : TransitionSafepointState(T) { | 187 : TransitionSafepointState(T) { |
| 192 // Native code is considered to be at a safepoint and so we mark it | 188 // Native code is considered to be at a safepoint and so we mark it |
| 193 // accordingly. | 189 // accordingly. |
| 194 ASSERT(T->execution_state() == Thread::kThreadInGenerated); | 190 ASSERT(T->execution_state() == Thread::kThreadInGenerated); |
| 195 T->set_execution_state(Thread::kThreadInNative); | 191 T->set_execution_state(Thread::kThreadInNative); |
| 196 T->EnterSafepoint(); | 192 T->EnterSafepoint(); |
| 197 } | 193 } |
| 198 | 194 |
| 199 ~TransitionGeneratedToNative() { | 195 ~TransitionGeneratedToNative() { |
| 200 // We are returning to generated code and so we are not at a safepoint | 196 // We are returning to generated code and so we are not at a safepoint |
| 201 // anymore. | 197 // anymore. |
| 202 ASSERT(thread()->execution_state() == Thread::kThreadInNative); | 198 ASSERT(thread()->execution_state() == Thread::kThreadInNative); |
| 203 thread()->ExitSafepoint(); | 199 thread()->ExitSafepoint(); |
| 204 thread()->set_execution_state(Thread::kThreadInGenerated); | 200 thread()->set_execution_state(Thread::kThreadInGenerated); |
| 205 } | 201 } |
| 206 | 202 |
| 207 private: | 203 private: |
| 208 DISALLOW_COPY_AND_ASSIGN(TransitionGeneratedToNative); | 204 DISALLOW_COPY_AND_ASSIGN(TransitionGeneratedToNative); |
| 209 }; | 205 }; |
| 210 | 206 |
| 211 | |
| 212 // TransitionVMToBlocked is used to transition the safepoint state of a | 207 // TransitionVMToBlocked is used to transition the safepoint state of a |
| 213 // thread from "running vm code" to "blocked on a monitor" and ensures | 208 // thread from "running vm code" to "blocked on a monitor" and ensures |
| 214 // that the state is reverted back to "running vm code" when | 209 // that the state is reverted back to "running vm code" when |
| 215 // exiting the scope/frame. | 210 // exiting the scope/frame. |
| 216 class TransitionVMToBlocked : public TransitionSafepointState { | 211 class TransitionVMToBlocked : public TransitionSafepointState { |
| 217 public: | 212 public: |
| 218 explicit TransitionVMToBlocked(Thread* T) : TransitionSafepointState(T) { | 213 explicit TransitionVMToBlocked(Thread* T) : TransitionSafepointState(T) { |
| 219 // A thread blocked on a monitor is considered to be at a safepoint. | 214 // A thread blocked on a monitor is considered to be at a safepoint. |
| 220 ASSERT(T->execution_state() == Thread::kThreadInVM); | 215 ASSERT(T->execution_state() == Thread::kThreadInVM); |
| 221 T->set_execution_state(Thread::kThreadInBlockedState); | 216 T->set_execution_state(Thread::kThreadInBlockedState); |
| 222 T->EnterSafepoint(); | 217 T->EnterSafepoint(); |
| 223 } | 218 } |
| 224 | 219 |
| 225 ~TransitionVMToBlocked() { | 220 ~TransitionVMToBlocked() { |
| 226 // We are returning to vm code and so we are not at a safepoint anymore. | 221 // We are returning to vm code and so we are not at a safepoint anymore. |
| 227 ASSERT(thread()->execution_state() == Thread::kThreadInBlockedState); | 222 ASSERT(thread()->execution_state() == Thread::kThreadInBlockedState); |
| 228 thread()->ExitSafepoint(); | 223 thread()->ExitSafepoint(); |
| 229 thread()->set_execution_state(Thread::kThreadInVM); | 224 thread()->set_execution_state(Thread::kThreadInVM); |
| 230 } | 225 } |
| 231 | 226 |
| 232 private: | 227 private: |
| 233 DISALLOW_COPY_AND_ASSIGN(TransitionVMToBlocked); | 228 DISALLOW_COPY_AND_ASSIGN(TransitionVMToBlocked); |
| 234 }; | 229 }; |
| 235 | 230 |
| 236 | |
| 237 // TransitionVMToNative is used to transition the safepoint state of a | 231 // TransitionVMToNative is used to transition the safepoint state of a |
| 238 // thread from "running vm code" to "running native code" and ensures | 232 // thread from "running vm code" to "running native code" and ensures |
| 239 // that the state is reverted back to "running vm code" when | 233 // that the state is reverted back to "running vm code" when |
| 240 // exiting the scope/frame. | 234 // exiting the scope/frame. |
| 241 class TransitionVMToNative : public TransitionSafepointState { | 235 class TransitionVMToNative : public TransitionSafepointState { |
| 242 public: | 236 public: |
| 243 explicit TransitionVMToNative(Thread* T) : TransitionSafepointState(T) { | 237 explicit TransitionVMToNative(Thread* T) : TransitionSafepointState(T) { |
| 244 // A thread running native code is considered to be at a safepoint. | 238 // A thread running native code is considered to be at a safepoint. |
| 245 ASSERT(T->execution_state() == Thread::kThreadInVM); | 239 ASSERT(T->execution_state() == Thread::kThreadInVM); |
| 246 T->set_execution_state(Thread::kThreadInNative); | 240 T->set_execution_state(Thread::kThreadInNative); |
| 247 T->EnterSafepoint(); | 241 T->EnterSafepoint(); |
| 248 } | 242 } |
| 249 | 243 |
| 250 ~TransitionVMToNative() { | 244 ~TransitionVMToNative() { |
| 251 // We are returning to vm code and so we are not at a safepoint anymore. | 245 // We are returning to vm code and so we are not at a safepoint anymore. |
| 252 ASSERT(thread()->execution_state() == Thread::kThreadInNative); | 246 ASSERT(thread()->execution_state() == Thread::kThreadInNative); |
| 253 thread()->ExitSafepoint(); | 247 thread()->ExitSafepoint(); |
| 254 thread()->set_execution_state(Thread::kThreadInVM); | 248 thread()->set_execution_state(Thread::kThreadInVM); |
| 255 } | 249 } |
| 256 | 250 |
| 257 private: | 251 private: |
| 258 DISALLOW_COPY_AND_ASSIGN(TransitionVMToNative); | 252 DISALLOW_COPY_AND_ASSIGN(TransitionVMToNative); |
| 259 }; | 253 }; |
| 260 | 254 |
| 261 | |
| 262 // TransitionVMToGenerated is used to transition the safepoint state of a | 255 // TransitionVMToGenerated is used to transition the safepoint state of a |
| 263 // thread from "running vm code" to "running generated code" and ensures | 256 // thread from "running vm code" to "running generated code" and ensures |
| 264 // that the state is reverted back to "running vm code" when | 257 // that the state is reverted back to "running vm code" when |
| 265 // exiting the scope/frame. | 258 // exiting the scope/frame. |
| 266 class TransitionVMToGenerated : public TransitionSafepointState { | 259 class TransitionVMToGenerated : public TransitionSafepointState { |
| 267 public: | 260 public: |
| 268 explicit TransitionVMToGenerated(Thread* T) : TransitionSafepointState(T) { | 261 explicit TransitionVMToGenerated(Thread* T) : TransitionSafepointState(T) { |
| 269 ASSERT(T == Thread::Current()); | 262 ASSERT(T == Thread::Current()); |
| 270 ASSERT(T->execution_state() == Thread::kThreadInVM); | 263 ASSERT(T->execution_state() == Thread::kThreadInVM); |
| 271 T->set_execution_state(Thread::kThreadInGenerated); | 264 T->set_execution_state(Thread::kThreadInGenerated); |
| 272 } | 265 } |
| 273 | 266 |
| 274 ~TransitionVMToGenerated() { | 267 ~TransitionVMToGenerated() { |
| 275 ASSERT(thread()->execution_state() == Thread::kThreadInGenerated); | 268 ASSERT(thread()->execution_state() == Thread::kThreadInGenerated); |
| 276 thread()->set_execution_state(Thread::kThreadInVM); | 269 thread()->set_execution_state(Thread::kThreadInVM); |
| 277 // Fast check to see if a safepoint is requested or not. | 270 // Fast check to see if a safepoint is requested or not. |
| 278 // We do the more expensive operation of blocking the thread | 271 // We do the more expensive operation of blocking the thread |
| 279 // only if a safepoint is requested. | 272 // only if a safepoint is requested. |
| 280 if (thread()->IsSafepointRequested()) { | 273 if (thread()->IsSafepointRequested()) { |
| 281 handler()->BlockForSafepoint(thread()); | 274 handler()->BlockForSafepoint(thread()); |
| 282 } | 275 } |
| 283 } | 276 } |
| 284 | 277 |
| 285 private: | 278 private: |
| 286 DISALLOW_COPY_AND_ASSIGN(TransitionVMToGenerated); | 279 DISALLOW_COPY_AND_ASSIGN(TransitionVMToGenerated); |
| 287 }; | 280 }; |
| 288 | 281 |
| 289 | |
| 290 // TransitionNativeToVM is used to transition the safepoint state of a | 282 // TransitionNativeToVM is used to transition the safepoint state of a |
| 291 // thread from "running native code" to "running vm code" and ensures | 283 // thread from "running native code" to "running vm code" and ensures |
| 292 // that the state is reverted back to "running native code" when | 284 // that the state is reverted back to "running native code" when |
| 293 // exiting the scope/frame. | 285 // exiting the scope/frame. |
| 294 class TransitionNativeToVM : public TransitionSafepointState { | 286 class TransitionNativeToVM : public TransitionSafepointState { |
| 295 public: | 287 public: |
| 296 explicit TransitionNativeToVM(Thread* T) : TransitionSafepointState(T) { | 288 explicit TransitionNativeToVM(Thread* T) : TransitionSafepointState(T) { |
| 297 // We are about to execute vm code and so we are not at a safepoint anymore. | 289 // We are about to execute vm code and so we are not at a safepoint anymore. |
| 298 ASSERT(T->execution_state() == Thread::kThreadInNative); | 290 ASSERT(T->execution_state() == Thread::kThreadInNative); |
| 299 T->ExitSafepoint(); | 291 T->ExitSafepoint(); |
| 300 T->set_execution_state(Thread::kThreadInVM); | 292 T->set_execution_state(Thread::kThreadInVM); |
| 301 } | 293 } |
| 302 | 294 |
| 303 ~TransitionNativeToVM() { | 295 ~TransitionNativeToVM() { |
| 304 // We are returning to native code and so we are at a safepoint. | 296 // We are returning to native code and so we are at a safepoint. |
| 305 ASSERT(thread()->execution_state() == Thread::kThreadInVM); | 297 ASSERT(thread()->execution_state() == Thread::kThreadInVM); |
| 306 thread()->set_execution_state(Thread::kThreadInNative); | 298 thread()->set_execution_state(Thread::kThreadInNative); |
| 307 thread()->EnterSafepoint(); | 299 thread()->EnterSafepoint(); |
| 308 } | 300 } |
| 309 | 301 |
| 310 private: | 302 private: |
| 311 DISALLOW_COPY_AND_ASSIGN(TransitionNativeToVM); | 303 DISALLOW_COPY_AND_ASSIGN(TransitionNativeToVM); |
| 312 }; | 304 }; |
| 313 | 305 |
| 314 | |
| 315 // TransitionToGenerated is used to transition the safepoint state of a | 306 // TransitionToGenerated is used to transition the safepoint state of a |
| 316 // thread from "running vm code" or "running native code" to | 307 // thread from "running vm code" or "running native code" to |
| 317 // "running generated code" and ensures that the state is reverted back | 308 // "running generated code" and ensures that the state is reverted back |
| 318 // to "running vm code" or "running native code" when exiting the | 309 // to "running vm code" or "running native code" when exiting the |
| 319 // scope/frame. | 310 // scope/frame. |
| 320 class TransitionToGenerated : public TransitionSafepointState { | 311 class TransitionToGenerated : public TransitionSafepointState { |
| 321 public: | 312 public: |
| 322 explicit TransitionToGenerated(Thread* T) | 313 explicit TransitionToGenerated(Thread* T) |
| 323 : TransitionSafepointState(T), execution_state_(T->execution_state()) { | 314 : TransitionSafepointState(T), execution_state_(T->execution_state()) { |
| 324 ASSERT(T == Thread::Current()); | 315 ASSERT(T == Thread::Current()); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 339 ASSERT(execution_state_ == Thread::kThreadInVM); | 330 ASSERT(execution_state_ == Thread::kThreadInVM); |
| 340 thread()->set_execution_state(Thread::kThreadInVM); | 331 thread()->set_execution_state(Thread::kThreadInVM); |
| 341 } | 332 } |
| 342 } | 333 } |
| 343 | 334 |
| 344 private: | 335 private: |
| 345 uint32_t execution_state_; | 336 uint32_t execution_state_; |
| 346 DISALLOW_COPY_AND_ASSIGN(TransitionToGenerated); | 337 DISALLOW_COPY_AND_ASSIGN(TransitionToGenerated); |
| 347 }; | 338 }; |
| 348 | 339 |
| 349 | |
| 350 // TransitionToVM is used to transition the safepoint state of a | 340 // TransitionToVM is used to transition the safepoint state of a |
| 351 // thread from "running native code" to "running vm code" | 341 // thread from "running native code" to "running vm code" |
| 352 // and ensures that the state is reverted back to "running native code" | 342 // and ensures that the state is reverted back to "running native code" |
| 353 // when exiting the scope/frame. | 343 // when exiting the scope/frame. |
| 354 // This transition helper is mainly used in the error path of the | 344 // This transition helper is mainly used in the error path of the |
| 355 // Dart API implementations where we sometimes do not have an explicit | 345 // Dart API implementations where we sometimes do not have an explicit |
| 356 // transition set up. | 346 // transition set up. |
| 357 class TransitionToVM : public TransitionSafepointState { | 347 class TransitionToVM : public TransitionSafepointState { |
| 358 public: | 348 public: |
| 359 explicit TransitionToVM(Thread* T) | 349 explicit TransitionToVM(Thread* T) |
| (...skipping 17 matching lines...) Expand all Loading... |
| 377 } | 367 } |
| 378 | 368 |
| 379 private: | 369 private: |
| 380 uint32_t execution_state_; | 370 uint32_t execution_state_; |
| 381 DISALLOW_COPY_AND_ASSIGN(TransitionToVM); | 371 DISALLOW_COPY_AND_ASSIGN(TransitionToVM); |
| 382 }; | 372 }; |
| 383 | 373 |
| 384 } // namespace dart | 374 } // namespace dart |
| 385 | 375 |
| 386 #endif // RUNTIME_VM_SAFEPOINT_H_ | 376 #endif // RUNTIME_VM_SAFEPOINT_H_ |
| OLD | NEW |