[vm/concurrency] Add SafepointMonitorUnlockScope to allow scoped unlocking of a monitor
In order to simplify code that needs to temporarily give up a monitor
lock, this CL adds a scoped object that releases the monitor on
construction and re-acquires it on destruction.
Issue https://github.com/dart-lang/sdk/issues/36097
TEST=Refactoring of existing code.
Change-Id: I004a04e54dcdaea009bfbef25d2a946a307e41c6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/187001
Reviewed-by: Alexander Aprelev <aam@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
diff --git a/runtime/vm/lockers.cc b/runtime/vm/lockers.cc
index 30e6ef8..a39f0c6 100644
--- a/runtime/vm/lockers.cc
+++ b/runtime/vm/lockers.cc
@@ -56,8 +56,7 @@
}
}
-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 @@
}
}
+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 7213808..b4557ae 100644
--- a/runtime/vm/lockers.h
+++ b/runtime/vm/lockers.h
@@ -259,19 +259,38 @@
*/
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 4303b5f..636aaa3 100644
--- a/runtime/vm/thread_test.cc
+++ b/runtime/vm/thread_test.cc
@@ -1102,4 +1102,23 @@
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