Index: runtime/vm/lockers.h |
diff --git a/runtime/vm/lockers.h b/runtime/vm/lockers.h |
index fd324f44811551673dd7a25f823abac28bac1b2e..4ad2751c1410920ff0ffef5061dd6b8eb1f56465 100644 |
--- a/runtime/vm/lockers.h |
+++ b/runtime/vm/lockers.h |
@@ -13,37 +13,153 @@ |
namespace dart { |
+/* |
+ * Normal mutex locker : |
+ * This locker abstraction should only be used when the enclosing code will |
srdjan
2016/03/01 16:46:23
s/will not/cannot/
siva
2016/03/01 18:59:54
Done.
|
+ * not trigger a safepoint. In debug mode this class increments the |
+ * no_safepoint_scope_depth variable for the current thread when the lock is |
+ * taken and decrements it when the lock is released. NOTE: please do not use |
+ * the passed in mutex object independent of the locker class, For example the |
+ * code below will not assert correctly: |
+ * { |
+ * MutexLocker ml(m); |
+ * .... |
+ * m->Exit(); |
+ * .... |
+ * m->Enter(); |
Cutch
2016/03/01 15:08:07
Why don't we make the Enter and Exit on the Mutex/
siva
2016/03/01 18:59:53
I tried this but there are a number of places wher
|
+ * ... |
+ * } |
+ * Always use the locker object even when the lock needs to be released |
+ * temporarily, e.g: |
+ * { |
+ * MutexLocker ml(m); |
+ * .... |
+ * ml.Exit(); |
+ * .... |
+ * ml.Enter(); |
+ * ... |
+ * } |
+ */ |
class MutexLocker : public ValueObject { |
public: |
- explicit MutexLocker(Mutex* mutex) : mutex_(mutex) { |
+ explicit MutexLocker(Mutex* mutex, bool no_safepoint_scope = true) |
Cutch
2016/03/01 15:08:07
Can we use an enum rather than a boolean as the se
siva
2016/03/01 18:59:54
An enum here seems like an overkill, we want the n
|
+ : mutex_(mutex), no_safepoint_scope_(no_safepoint_scope) { |
ASSERT(mutex != NULL); |
- // TODO(iposva): Consider adding a no GC scope here. |
+#if defined(DEBUG) |
+ if (no_safepoint_scope_) { |
+ Thread* thread = Thread::Current(); |
+ if (thread != NULL) { |
+ thread->IncrementNoSafepointScopeDepth(); |
+ } else { |
+ no_safepoint_scope_ = false; |
+ } |
+ } |
+#endif |
mutex_->Lock(); |
} |
virtual ~MutexLocker() { |
mutex_->Unlock(); |
- // TODO(iposva): Consider decrementing the no GC scope here. |
+#if defined(DEBUG) |
+ if (no_safepoint_scope_) { |
+ Thread::Current()->DecrementNoSafepointScopeDepth(); |
+ } |
+#endif |
+ } |
+ |
+ void Lock() const { |
+#if defined(DEBUG) |
+ if (no_safepoint_scope_) { |
+ Thread::Current()->IncrementNoSafepointScopeDepth(); |
+ } |
+#endif |
+ mutex_->Lock(); |
+ } |
+ void Unlock() const { |
+ mutex_->Unlock(); |
+#if defined(DEBUG) |
+ if (no_safepoint_scope_) { |
+ Thread::Current()->DecrementNoSafepointScopeDepth(); |
+ } |
+#endif |
} |
private: |
Mutex* const mutex_; |
+ bool no_safepoint_scope_; |
DISALLOW_COPY_AND_ASSIGN(MutexLocker); |
}; |
- |
+/* |
+ * Normal monitor locker : |
+ * This locker abstraction should only be used when the enclosing code will |
srdjan
2016/03/01 16:46:23
ditto?
siva
2016/03/01 18:59:53
Done.
|
+ * not trigger a safepoint. In debug mode this class increments the |
+ * no_safepoint_scope_depth variable for the current thread when the lock is |
+ * taken and decrements it when the lock is released. NOTE: please do not use |
+ * the passed in mutex object independent of the locker class, For example the |
+ * code below will not assert correctly: |
+ * { |
+ * MonitorLocker ml(m); |
+ * .... |
+ * m->Exit(); |
+ * .... |
+ * m->Enter(); |
+ * ... |
+ * } |
+ * Always use the locker object even when the lock needs to be released |
+ * temporarily, e.g: |
+ * { |
+ * MonitorLocker ml(m); |
+ * .... |
+ * ml.Exit(); |
+ * .... |
+ * ml.Enter(); |
+ * ... |
+ * } |
+ */ |
class MonitorLocker : public ValueObject { |
public: |
- explicit MonitorLocker(Monitor* monitor) : monitor_(monitor) { |
+ explicit MonitorLocker(Monitor* monitor, bool no_safepoint_scope = true) |
+ : monitor_(monitor), no_safepoint_scope_(no_safepoint_scope) { |
ASSERT(monitor != NULL); |
- // TODO(iposva): Consider adding a no GC scope here. |
+#if defined(DEBUG) |
+ if (no_safepoint_scope_) { |
+ Thread* thread = Thread::Current(); |
+ if (thread != NULL) { |
+ thread->IncrementNoSafepointScopeDepth(); |
+ } else { |
+ no_safepoint_scope_ = false; |
+ } |
+ } |
+#endif |
monitor_->Enter(); |
} |
virtual ~MonitorLocker() { |
monitor_->Exit(); |
- // TODO(iposva): Consider decrementing the no GC scope here. |
+#if defined(DEBUG) |
Cutch
2016/03/01 15:08:07
here and elsewhere:
DEBUG_ONLY(
)
siva
2016/03/01 18:59:54
I looked at uses of DEBUG_ONLY and looks like the
|
+ if (no_safepoint_scope_) { |
+ Thread::Current()->DecrementNoSafepointScopeDepth(); |
+ } |
+#endif |
+ } |
+ |
+ void Enter() const { |
+#if defined(DEBUG) |
+ if (no_safepoint_scope_) { |
+ Thread::Current()->IncrementNoSafepointScopeDepth(); |
+ } |
+#endif |
+ monitor_->Enter(); |
+ } |
+ void Exit() const { |
+ monitor_->Exit(); |
+#if defined(DEBUG) |
+ if (no_safepoint_scope_) { |
+ Thread::Current()->DecrementNoSafepointScopeDepth(); |
+ } |
+#endif |
} |
Monitor::WaitResult Wait(int64_t millis = Monitor::kNoTimeout) { |
@@ -67,16 +183,29 @@ class MonitorLocker : public ValueObject { |
private: |
Monitor* const monitor_; |
+ bool no_safepoint_scope_; |
DISALLOW_COPY_AND_ASSIGN(MonitorLocker); |
}; |
- |
-// SafepointMutexLocker objects are used in code where the locks are |
-// more coarse grained and a safepoint operation could be potentially |
-// triggered while holding this lock. This ensures that other threads |
-// which try to acquire the same lock will be marked as being at a |
-// safepoint when they are blocked. |
+/* |
+ * Safepoint mutex locker : |
+ * This locker abstraction should be used when the lock is more coarse |
Cutch
2016/03/01 15:08:07
I don't see why the granularity of the lock matter
siva
2016/03/01 18:59:53
Changed the comment to remove the coarse wording.
|
+ * grained and the enclosing code could potentially trigger a safepoint. |
+ * This locker ensures that other threads that try to acquire the same lock |
+ * will be marked as being at a safepoint if they get blocked trying to |
+ * acquire the lock. |
+ * NOTE: please do not use the passed in mutex object independent of the locker |
+ * class, For example the code below will not work correctly: |
+ * { |
+ * SafepointMutexLocker ml(m); |
+ * .... |
+ * m->Exit(); |
+ * .... |
+ * m->Enter(); |
+ * ... |
+ * } |
+ */ |
class SafepointMutexLocker : public ValueObject { |
public: |
explicit SafepointMutexLocker(Mutex* mutex); |
@@ -90,6 +219,39 @@ class SafepointMutexLocker : public ValueObject { |
DISALLOW_COPY_AND_ASSIGN(SafepointMutexLocker); |
}; |
+/* |
+ * Safepoint monitor locker : |
+ * This locker abstraction should be used when the lock is more coarse |
+ * grained and the enclosing code could potentially trigger a safepoint. |
+ * This locker ensures that other threads that try to acquire the same lock |
+ * will be marked as being at a safepoint if they get blocked trying to |
+ * acquire the lock. |
+ * NOTE: please do not use the passed in monitor object independent of the locker |
Cutch
2016/03/01 15:08:07
line length
siva
2016/03/01 18:59:53
Done.
|
+ * class, For example the code below will not work correctly: |
+ * { |
+ * SafepointMonitorLocker ml(m); |
+ * .... |
+ * m->Exit(); |
+ * .... |
+ * m->Enter(); |
+ * ... |
+ * } |
+ */ |
+class SafepointMonitorLocker : public ValueObject { |
+ public: |
+ explicit SafepointMonitorLocker(Monitor* monitor); |
+ virtual ~SafepointMonitorLocker() { |
+ monitor_->Exit(); |
+ } |
+ |
+ Monitor::WaitResult Wait(int64_t millis = Monitor::kNoTimeout); |
+ |
+ private: |
+ Monitor* const monitor_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(SafepointMonitorLocker); |
+}; |
+ |
} // namespace dart |