[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>
This commit is contained in:
Martin Kustermann 2021-03-02 13:11:42 +00:00 committed by commit-bot@chromium.org
parent af4757dd0b
commit f3740ced59
3 changed files with 45 additions and 4 deletions

View file

@ -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) {

View file

@ -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() {}

View file

@ -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