| Index: runtime/vm/lockers.h
|
| diff --git a/runtime/vm/lockers.h b/runtime/vm/lockers.h
|
| index fd324f44811551673dd7a25f823abac28bac1b2e..a0b1a179be8f0aacce55c0d53b35777e442ee7b6 100644
|
| --- a/runtime/vm/lockers.h
|
| +++ b/runtime/vm/lockers.h
|
| @@ -13,37 +13,156 @@
|
|
|
| namespace dart {
|
|
|
| +const bool kNoSafepointScope = true;
|
| +const bool kDontAssertNoSafepointScope = false;
|
| +
|
| +/*
|
| + * Normal mutex locker :
|
| + * This locker abstraction should only be used when the enclosing code can
|
| + * 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();
|
| + * ...
|
| + * }
|
| + * 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)
|
| + : 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 can
|
| + * 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)
|
| + 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 +186,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 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 +222,39 @@ class SafepointMutexLocker : public ValueObject {
|
| DISALLOW_COPY_AND_ASSIGN(SafepointMutexLocker);
|
| };
|
|
|
| +/*
|
| + * Safepoint monitor locker :
|
| + * This locker abstraction should be used when 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 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
|
|
|
|
|
|
|