Chromium Code Reviews| 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 |