diff --git a/runtime/vm/lockers.cc b/runtime/vm/lockers.cc index 30e6ef831fe..a39f0c68fe0 100644 --- a/runtime/vm/lockers.cc +++ b/runtime/vm/lockers.cc @@ -56,8 +56,7 @@ SafepointMutexLocker::SafepointMutexLocker(ThreadState* thread, Mutex* mutex) } } -SafepointMonitorLocker::SafepointMonitorLocker(Monitor* monitor) - : monitor_(monitor) { +void SafepointMonitorLocker::AcquireLock() { ASSERT(monitor_ != NULL); if (!monitor_->TryEnter()) { // We did not get the lock and could potentially block, so transition @@ -72,6 +71,10 @@ SafepointMonitorLocker::SafepointMonitorLocker(Monitor* monitor) } } +void SafepointMonitorLocker::ReleaseLock() { + monitor_->Exit(); +} + Monitor::WaitResult SafepointMonitorLocker::Wait(int64_t millis) { Thread* thread = Thread::Current(); if (thread != NULL) { diff --git a/runtime/vm/lockers.h b/runtime/vm/lockers.h index 72138087a4e..b4557ae7c63 100644 --- a/runtime/vm/lockers.h +++ b/runtime/vm/lockers.h @@ -259,19 +259,38 @@ class SafepointMutexLocker : public StackResource { */ class SafepointMonitorLocker : public ValueObject { public: - explicit SafepointMonitorLocker(Monitor* monitor); - virtual ~SafepointMonitorLocker() { monitor_->Exit(); } + explicit SafepointMonitorLocker(Monitor* monitor) : monitor_(monitor) { + AcquireLock(); + } + virtual ~SafepointMonitorLocker() { ReleaseLock(); } Monitor::WaitResult Wait(int64_t millis = Monitor::kNoTimeout); void NotifyAll() { monitor_->NotifyAll(); } private: + friend class SafepointMonitorUnlockScope; + + void AcquireLock(); + void ReleaseLock(); + Monitor* const monitor_; DISALLOW_COPY_AND_ASSIGN(SafepointMonitorLocker); }; +class SafepointMonitorUnlockScope : public ValueObject { + public: + explicit SafepointMonitorUnlockScope(SafepointMonitorLocker* locker) + : locker_(locker) { + locker_->ReleaseLock(); + } + ~SafepointMonitorUnlockScope() { locker_->AcquireLock(); } + + private: + SafepointMonitorLocker* locker_; +}; + class RwLock { public: RwLock() {} diff --git a/runtime/vm/thread_test.cc b/runtime/vm/thread_test.cc index 4303b5f2756..636aaa379e0 100644 --- a/runtime/vm/thread_test.cc +++ b/runtime/vm/thread_test.cc @@ -1102,4 +1102,23 @@ ISOLATE_UNIT_TEST_CASE(SafepointRwLockExclusiveNestedWriter_Regress44000) { EXPECT(state.elapsed_us > 2 * 500 * 1000); } +ISOLATE_UNIT_TEST_CASE(SafepointMonitorUnlockScope) { + // This test uses ASSERT instead of EXPECT because IsOwnedByCurrentThread is + // only available in debug mode. Since our vm/cc tests run in DEBUG mode that + // is sufficent for this test. + Monitor monitor; + { + SafepointMonitorLocker ml(&monitor); + ASSERT(monitor.IsOwnedByCurrentThread()); + { + SafepointMonitorUnlockScope ml_unlocker(&ml); + ASSERT(!monitor.IsOwnedByCurrentThread()); + { + SafepointMonitorLocker inner_ml(&monitor); + ASSERT(monitor.IsOwnedByCurrentThread()); + } + } + } +} + } // namespace dart