OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 VM_LOCKERS_H_ | 5 #ifndef VM_LOCKERS_H_ |
6 #define VM_LOCKERS_H_ | 6 #define VM_LOCKERS_H_ |
7 | 7 |
8 #include "platform/assert.h" | 8 #include "platform/assert.h" |
9 #include "vm/allocation.h" | 9 #include "vm/allocation.h" |
10 #include "vm/globals.h" | 10 #include "vm/globals.h" |
11 #include "vm/isolate.h" | 11 #include "vm/isolate.h" |
12 #include "vm/os_thread.h" | 12 #include "vm/os_thread.h" |
13 | 13 |
14 namespace dart { | 14 namespace dart { |
15 | 15 |
| 16 const bool kNoSafepointScope = true; |
| 17 const bool kDontAssertNoSafepointScope = false; |
| 18 |
| 19 /* |
| 20 * Normal mutex locker : |
| 21 * This locker abstraction should only be used when the enclosing code can |
| 22 * not trigger a safepoint. In debug mode this class increments the |
| 23 * no_safepoint_scope_depth variable for the current thread when the lock is |
| 24 * taken and decrements it when the lock is released. NOTE: please do not use |
| 25 * the passed in mutex object independent of the locker class, For example the |
| 26 * code below will not assert correctly: |
| 27 * { |
| 28 * MutexLocker ml(m); |
| 29 * .... |
| 30 * m->Exit(); |
| 31 * .... |
| 32 * m->Enter(); |
| 33 * ... |
| 34 * } |
| 35 * Always use the locker object even when the lock needs to be released |
| 36 * temporarily, e.g: |
| 37 * { |
| 38 * MutexLocker ml(m); |
| 39 * .... |
| 40 * ml.Exit(); |
| 41 * .... |
| 42 * ml.Enter(); |
| 43 * ... |
| 44 * } |
| 45 */ |
16 class MutexLocker : public ValueObject { | 46 class MutexLocker : public ValueObject { |
17 public: | 47 public: |
18 explicit MutexLocker(Mutex* mutex) : mutex_(mutex) { | 48 explicit MutexLocker(Mutex* mutex, bool no_safepoint_scope = true) |
| 49 : mutex_(mutex), no_safepoint_scope_(no_safepoint_scope) { |
19 ASSERT(mutex != NULL); | 50 ASSERT(mutex != NULL); |
20 // TODO(iposva): Consider adding a no GC scope here. | 51 #if defined(DEBUG) |
| 52 if (no_safepoint_scope_) { |
| 53 Thread* thread = Thread::Current(); |
| 54 if (thread != NULL) { |
| 55 thread->IncrementNoSafepointScopeDepth(); |
| 56 } else { |
| 57 no_safepoint_scope_ = false; |
| 58 } |
| 59 } |
| 60 #endif |
21 mutex_->Lock(); | 61 mutex_->Lock(); |
22 } | 62 } |
23 | 63 |
24 virtual ~MutexLocker() { | 64 virtual ~MutexLocker() { |
25 mutex_->Unlock(); | 65 mutex_->Unlock(); |
26 // TODO(iposva): Consider decrementing the no GC scope here. | 66 #if defined(DEBUG) |
| 67 if (no_safepoint_scope_) { |
| 68 Thread::Current()->DecrementNoSafepointScopeDepth(); |
| 69 } |
| 70 #endif |
| 71 } |
| 72 |
| 73 void Lock() const { |
| 74 #if defined(DEBUG) |
| 75 if (no_safepoint_scope_) { |
| 76 Thread::Current()->IncrementNoSafepointScopeDepth(); |
| 77 } |
| 78 #endif |
| 79 mutex_->Lock(); |
| 80 } |
| 81 void Unlock() const { |
| 82 mutex_->Unlock(); |
| 83 #if defined(DEBUG) |
| 84 if (no_safepoint_scope_) { |
| 85 Thread::Current()->DecrementNoSafepointScopeDepth(); |
| 86 } |
| 87 #endif |
27 } | 88 } |
28 | 89 |
29 private: | 90 private: |
30 Mutex* const mutex_; | 91 Mutex* const mutex_; |
| 92 bool no_safepoint_scope_; |
31 | 93 |
32 DISALLOW_COPY_AND_ASSIGN(MutexLocker); | 94 DISALLOW_COPY_AND_ASSIGN(MutexLocker); |
33 }; | 95 }; |
34 | 96 |
35 | 97 /* |
| 98 * Normal monitor locker : |
| 99 * This locker abstraction should only be used when the enclosing code can |
| 100 * not trigger a safepoint. In debug mode this class increments the |
| 101 * no_safepoint_scope_depth variable for the current thread when the lock is |
| 102 * taken and decrements it when the lock is released. NOTE: please do not use |
| 103 * the passed in mutex object independent of the locker class, For example the |
| 104 * code below will not assert correctly: |
| 105 * { |
| 106 * MonitorLocker ml(m); |
| 107 * .... |
| 108 * m->Exit(); |
| 109 * .... |
| 110 * m->Enter(); |
| 111 * ... |
| 112 * } |
| 113 * Always use the locker object even when the lock needs to be released |
| 114 * temporarily, e.g: |
| 115 * { |
| 116 * MonitorLocker ml(m); |
| 117 * .... |
| 118 * ml.Exit(); |
| 119 * .... |
| 120 * ml.Enter(); |
| 121 * ... |
| 122 * } |
| 123 */ |
36 class MonitorLocker : public ValueObject { | 124 class MonitorLocker : public ValueObject { |
37 public: | 125 public: |
38 explicit MonitorLocker(Monitor* monitor) : monitor_(monitor) { | 126 explicit MonitorLocker(Monitor* monitor, bool no_safepoint_scope = true) |
| 127 : monitor_(monitor), no_safepoint_scope_(no_safepoint_scope) { |
39 ASSERT(monitor != NULL); | 128 ASSERT(monitor != NULL); |
40 // TODO(iposva): Consider adding a no GC scope here. | 129 #if defined(DEBUG) |
| 130 if (no_safepoint_scope_) { |
| 131 Thread* thread = Thread::Current(); |
| 132 if (thread != NULL) { |
| 133 thread->IncrementNoSafepointScopeDepth(); |
| 134 } else { |
| 135 no_safepoint_scope_ = false; |
| 136 } |
| 137 } |
| 138 #endif |
41 monitor_->Enter(); | 139 monitor_->Enter(); |
42 } | 140 } |
43 | 141 |
44 virtual ~MonitorLocker() { | 142 virtual ~MonitorLocker() { |
45 monitor_->Exit(); | 143 monitor_->Exit(); |
46 // TODO(iposva): Consider decrementing the no GC scope here. | 144 #if defined(DEBUG) |
| 145 if (no_safepoint_scope_) { |
| 146 Thread::Current()->DecrementNoSafepointScopeDepth(); |
| 147 } |
| 148 #endif |
| 149 } |
| 150 |
| 151 void Enter() const { |
| 152 #if defined(DEBUG) |
| 153 if (no_safepoint_scope_) { |
| 154 Thread::Current()->IncrementNoSafepointScopeDepth(); |
| 155 } |
| 156 #endif |
| 157 monitor_->Enter(); |
| 158 } |
| 159 void Exit() const { |
| 160 monitor_->Exit(); |
| 161 #if defined(DEBUG) |
| 162 if (no_safepoint_scope_) { |
| 163 Thread::Current()->DecrementNoSafepointScopeDepth(); |
| 164 } |
| 165 #endif |
47 } | 166 } |
48 | 167 |
49 Monitor::WaitResult Wait(int64_t millis = Monitor::kNoTimeout) { | 168 Monitor::WaitResult Wait(int64_t millis = Monitor::kNoTimeout) { |
50 return monitor_->Wait(millis); | 169 return monitor_->Wait(millis); |
51 } | 170 } |
52 | 171 |
53 Monitor::WaitResult WaitWithSafepointCheck( | 172 Monitor::WaitResult WaitWithSafepointCheck( |
54 Thread* thread, int64_t millis = Monitor::kNoTimeout); | 173 Thread* thread, int64_t millis = Monitor::kNoTimeout); |
55 | 174 |
56 Monitor::WaitResult WaitMicros(int64_t micros = Monitor::kNoTimeout) { | 175 Monitor::WaitResult WaitMicros(int64_t micros = Monitor::kNoTimeout) { |
57 return monitor_->WaitMicros(micros); | 176 return monitor_->WaitMicros(micros); |
58 } | 177 } |
59 | 178 |
60 void Notify() { | 179 void Notify() { |
61 monitor_->Notify(); | 180 monitor_->Notify(); |
62 } | 181 } |
63 | 182 |
64 void NotifyAll() { | 183 void NotifyAll() { |
65 monitor_->NotifyAll(); | 184 monitor_->NotifyAll(); |
66 } | 185 } |
67 | 186 |
68 private: | 187 private: |
69 Monitor* const monitor_; | 188 Monitor* const monitor_; |
| 189 bool no_safepoint_scope_; |
70 | 190 |
71 DISALLOW_COPY_AND_ASSIGN(MonitorLocker); | 191 DISALLOW_COPY_AND_ASSIGN(MonitorLocker); |
72 }; | 192 }; |
73 | 193 |
74 | 194 /* |
75 // SafepointMutexLocker objects are used in code where the locks are | 195 * Safepoint mutex locker : |
76 // more coarse grained and a safepoint operation could be potentially | 196 * This locker abstraction should be used when the enclosing code could |
77 // triggered while holding this lock. This ensures that other threads | 197 * potentially trigger a safepoint. |
78 // which try to acquire the same lock will be marked as being at a | 198 * This locker ensures that other threads that try to acquire the same lock |
79 // safepoint when they are blocked. | 199 * will be marked as being at a safepoint if they get blocked trying to |
| 200 * acquire the lock. |
| 201 * NOTE: please do not use the passed in mutex object independent of the locker |
| 202 * class, For example the code below will not work correctly: |
| 203 * { |
| 204 * SafepointMutexLocker ml(m); |
| 205 * .... |
| 206 * m->Exit(); |
| 207 * .... |
| 208 * m->Enter(); |
| 209 * ... |
| 210 * } |
| 211 */ |
80 class SafepointMutexLocker : public ValueObject { | 212 class SafepointMutexLocker : public ValueObject { |
81 public: | 213 public: |
82 explicit SafepointMutexLocker(Mutex* mutex); | 214 explicit SafepointMutexLocker(Mutex* mutex); |
83 virtual ~SafepointMutexLocker() { | 215 virtual ~SafepointMutexLocker() { |
84 mutex_->Unlock(); | 216 mutex_->Unlock(); |
85 } | 217 } |
86 | 218 |
87 private: | 219 private: |
88 Mutex* const mutex_; | 220 Mutex* const mutex_; |
89 | 221 |
90 DISALLOW_COPY_AND_ASSIGN(SafepointMutexLocker); | 222 DISALLOW_COPY_AND_ASSIGN(SafepointMutexLocker); |
91 }; | 223 }; |
92 | 224 |
| 225 /* |
| 226 * Safepoint monitor locker : |
| 227 * This locker abstraction should be used when the enclosing code could |
| 228 * potentially trigger a safepoint. |
| 229 * This locker ensures that other threads that try to acquire the same lock |
| 230 * will be marked as being at a safepoint if they get blocked trying to |
| 231 * acquire the lock. |
| 232 * NOTE: please do not use the passed in monitor object independent of the |
| 233 * locker class, For example the code below will not work correctly: |
| 234 * { |
| 235 * SafepointMonitorLocker ml(m); |
| 236 * .... |
| 237 * m->Exit(); |
| 238 * .... |
| 239 * m->Enter(); |
| 240 * ... |
| 241 * } |
| 242 */ |
| 243 class SafepointMonitorLocker : public ValueObject { |
| 244 public: |
| 245 explicit SafepointMonitorLocker(Monitor* monitor); |
| 246 virtual ~SafepointMonitorLocker() { |
| 247 monitor_->Exit(); |
| 248 } |
| 249 |
| 250 Monitor::WaitResult Wait(int64_t millis = Monitor::kNoTimeout); |
| 251 |
| 252 private: |
| 253 Monitor* const monitor_; |
| 254 |
| 255 DISALLOW_COPY_AND_ASSIGN(SafepointMonitorLocker); |
| 256 }; |
| 257 |
93 } // namespace dart | 258 } // namespace dart |
94 | 259 |
95 | 260 |
96 #endif // VM_LOCKERS_H_ | 261 #endif // VM_LOCKERS_H_ |
OLD | NEW |