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() {} |
| 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 |