[vm/concurrency] Make SafepointMutexLocker inherit from StackResource
The SafepointMutexLocker class already has a virtual destructor and was
therefore probably intended to be called when a longjmp() crosses it.
Issue https://github.com/dart-lang/sdk/issues/36097
TEST=Added vm/cc tests in the CL.
Change-Id: Ifcfe51db733c4451be5be688df0c34004b98c3cc
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/174644
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
diff --git a/runtime/vm/lockers.cc b/runtime/vm/lockers.cc
index 7ad731d..cb04006 100644
--- a/runtime/vm/lockers.cc
+++ b/runtime/vm/lockers.cc
@@ -40,7 +40,8 @@
return result;
}
-SafepointMutexLocker::SafepointMutexLocker(Mutex* mutex) : mutex_(mutex) {
+SafepointMutexLocker::SafepointMutexLocker(ThreadState* thread, Mutex* mutex)
+ : StackResource(thread), mutex_(mutex) {
ASSERT(mutex != NULL);
if (!mutex_->TryLock()) {
// We did not get the lock and could potentially block, so transition
diff --git a/runtime/vm/lockers.h b/runtime/vm/lockers.h
index 94a8070..d5b2576 100644
--- a/runtime/vm/lockers.h
+++ b/runtime/vm/lockers.h
@@ -226,9 +226,11 @@
* ...
* }
*/
-class SafepointMutexLocker : public ValueObject {
+class SafepointMutexLocker : public StackResource {
public:
- explicit SafepointMutexLocker(Mutex* mutex);
+ explicit SafepointMutexLocker(Mutex* mutex)
+ : SafepointMutexLocker(ThreadState::Current(), mutex) {}
+ SafepointMutexLocker(ThreadState* thread, Mutex* mutex);
virtual ~SafepointMutexLocker() { mutex_->Unlock(); }
private:
diff --git a/runtime/vm/thread_test.cc b/runtime/vm/thread_test.cc
index aaedbb7..95a0839 100644
--- a/runtime/vm/thread_test.cc
+++ b/runtime/vm/thread_test.cc
@@ -1029,6 +1029,38 @@
EXPECT(!lock.IsCurrentThreadWriter());
}
+template <typename LockType, typename LockerType>
+static void RunLockerWithLongJumpTest() {
+ const intptr_t kNumIterations = 5;
+ intptr_t execution_count = 0;
+ intptr_t thrown_count = 0;
+ LockType lock;
+ for (intptr_t i = 0; i < kNumIterations; ++i) {
+ LongJumpScope jump;
+ if (setjmp(*jump.Set()) == 0) {
+ LockerType locker(Thread::Current(), &lock);
+ execution_count++;
+ Thread::Current()->long_jump_base()->Jump(
+ 1, Object::background_compilation_error());
+ } else {
+ thrown_count++;
+ }
+ }
+ EXPECT_EQ(kNumIterations, execution_count);
+ EXPECT_EQ(kNumIterations, thrown_count);
+}
+ISOLATE_UNIT_TEST_CASE(SafepointRwLockWriteWithLongJmp) {
+ RunLockerWithLongJumpTest<SafepointRwLock, SafepointWriteRwLocker>();
+}
+
+ISOLATE_UNIT_TEST_CASE(SafepointRwLockReadWithLongJmp) {
+ RunLockerWithLongJumpTest<SafepointRwLock, SafepointReadRwLocker>();
+}
+
+ISOLATE_UNIT_TEST_CASE(SafepointMutexLockerWithLongJmp) {
+ RunLockerWithLongJumpTest<Mutex, SafepointMutexLocker>();
+}
+
struct ReaderThreadState {
ThreadJoinId reader_id = OSThread::kInvalidThreadJoinId;
SafepointRwLock* rw_lock = nullptr;