Correct behavior of thread suspension around Raw monitors
The interaction between raw monitors and thread suspension was
different than some real-world agents expected. Real-world agents rely
on the RawMonitorWait function acting as a suspend point.
Changed the raw-monitor implementation to match this behavior.
Add tests for this behavior and for the behavior of RawMonitorExit
(which does not act as a suspend point).
Bug: 66904725
Bug: 62821960
Test: ./test.py --host -j50
Test: ./art/tools/run-libjdwp-tests.sh --mode=host
Change-Id: Ibaed6a7e6910b7b612f0fb1313958857fbe54595
diff --git a/openjdkjvmti/ti_monitor.cc b/openjdkjvmti/ti_monitor.cc
index 7db0566..94408ba 100644
--- a/openjdkjvmti/ti_monitor.cc
+++ b/openjdkjvmti/ti_monitor.cc
@@ -169,6 +169,7 @@
}
size_t old_count = count_;
+ DCHECK_GT(old_count, 0u);
count_ = 0;
owner_.store(nullptr, std::memory_order_relaxed);
@@ -176,12 +177,19 @@
{
std::unique_lock<std::mutex> lk(mutex_, std::adopt_lock);
how_to_wait(lk);
- lk.release(); // Do not unlock the mutex.
+ // Here we release the mutex. We will get it back below. We first need to do a suspend-check
+ // without holding it however. This is done in the MonitorEnter function.
+ // TODO We could do this more efficiently.
+ // We hold the mutex_ but the overall monitor is not owned at this point.
+ CHECK(owner_.load(std::memory_order_relaxed) == nullptr);
+ DCHECK_EQ(0u, count_);
}
- DCHECK(owner_.load(std::memory_order_relaxed) == nullptr);
- owner_.store(self, std::memory_order_relaxed);
- DCHECK_EQ(0u, count_);
+ // Reaquire the mutex/monitor, also go to sleep if we were suspended.
+ MonitorEnter(self);
+ CHECK(owner_.load(std::memory_order_relaxed) == self);
+ DCHECK_EQ(1u, count_);
+ // Reset the count.
count_ = old_count;
return true;