Fix issue with RawMonitors around thread suspension.
Investigation of real-world JVMTI agents revealed that some rely on
the RawMonitorEnter function acting as a Java suspend point. If it
fails to act as one the agent could end up deadlocked.
Test: ./test.py --host -j50
Bug: 62821960
Bug: 34415266
Change-Id: I3daf5c49c1c9870e1f69eebfd4c6f2ad15224510
diff --git a/openjdkjvmti/ti_thread.cc b/openjdkjvmti/ti_thread.cc
index b0a1a85..27d01ea 100644
--- a/openjdkjvmti/ti_thread.cc
+++ b/openjdkjvmti/ti_thread.cc
@@ -85,7 +85,8 @@
if (name != "JDWP" &&
name != "Signal Catcher" &&
!android::base::StartsWith(name, "Jit thread pool")) {
- LOG(FATAL) << "Unexpected thread before start: " << name;
+ LOG(FATAL) << "Unexpected thread before start: " << name << " id: "
+ << self->GetThreadId();
}
}
return;
@@ -413,13 +414,24 @@
}
// Suspends the current thread if it has any suspend requests on it.
-static void SuspendCheck(art::Thread* self)
- REQUIRES(!art::Locks::mutator_lock_, !art::Locks::user_code_suspension_lock_) {
+void ThreadUtil::SuspendCheck(art::Thread* self) {
art::ScopedObjectAccess soa(self);
// Really this is only needed if we are in FastJNI and actually have the mutator_lock_ already.
self->FullSuspendCheck();
}
+bool ThreadUtil::WouldSuspendForUserCodeLocked(art::Thread* self) {
+ DCHECK(self == art::Thread::Current());
+ art::MutexLock tscl_mu(self, *art::Locks::thread_suspend_count_lock_);
+ return self->GetUserCodeSuspendCount() != 0;
+}
+
+bool ThreadUtil::WouldSuspendForUserCode(art::Thread* self) {
+ DCHECK(self == art::Thread::Current());
+ art::MutexLock ucsl_mu(self, *art::Locks::user_code_suspension_lock_);
+ return WouldSuspendForUserCodeLocked(self);
+}
+
jvmtiError ThreadUtil::GetThreadState(jvmtiEnv* env ATTRIBUTE_UNUSED,
jthread thread,
jint* thread_state_ptr) {
@@ -435,13 +447,10 @@
do {
SuspendCheck(self);
art::MutexLock ucsl_mu(self, *art::Locks::user_code_suspension_lock_);
- {
- art::MutexLock tscl_mu(self, *art::Locks::thread_suspend_count_lock_);
- if (self->GetUserCodeSuspendCount() != 0) {
- // Make sure we won't be suspended in the middle of holding the thread_suspend_count_lock_
- // by a user-code suspension. We retry and do another SuspendCheck to clear this.
- continue;
- }
+ if (WouldSuspendForUserCodeLocked(self)) {
+ // Make sure we won't be suspended in the middle of holding the thread_suspend_count_lock_ by
+ // a user-code suspension. We retry and do another SuspendCheck to clear this.
+ continue;
}
art::ScopedObjectAccess soa(self);
art::MutexLock tll_mu(self, *art::Locks::thread_list_lock_);
@@ -657,6 +666,9 @@
jvmtiStartFunction proc,
const void* arg,
jint priority) {
+ if (!PhaseUtil::IsLivePhase()) {
+ return ERR(WRONG_PHASE);
+ }
if (priority < JVMTI_THREAD_MIN_PRIORITY || priority > JVMTI_THREAD_MAX_PRIORITY) {
return ERR(INVALID_PRIORITY);
}
@@ -703,15 +715,12 @@
// before continuing.
SuspendCheck(self);
art::MutexLock mu(self, *art::Locks::user_code_suspension_lock_);
- {
- art::MutexLock thread_suspend_count_mu(self, *art::Locks::thread_suspend_count_lock_);
+ if (WouldSuspendForUserCodeLocked(self)) {
// Make sure we won't be suspended in the middle of holding the thread_suspend_count_lock_ by
// a user-code suspension. We retry and do another SuspendCheck to clear this.
- if (self->GetUserCodeSuspendCount() != 0) {
- continue;
- }
- // We are not going to be suspended by user code from now on.
+ continue;
}
+ // We are not going to be suspended by user code from now on.
{
art::ScopedObjectAccess soa(self);
art::MutexLock thread_list_mu(self, *art::Locks::thread_list_lock_);
@@ -798,13 +807,10 @@
do {
SuspendCheck(self);
art::MutexLock ucsl_mu(self, *art::Locks::user_code_suspension_lock_);
- {
- art::MutexLock tscl_mu(self, *art::Locks::thread_suspend_count_lock_);
+ if (WouldSuspendForUserCodeLocked(self)) {
// Make sure we won't be suspended in the middle of holding the thread_suspend_count_lock_ by
// a user-code suspension. We retry and do another SuspendCheck to clear this.
- if (self->GetUserCodeSuspendCount() != 0) {
- continue;
- }
+ continue;
}
// From now on we know we cannot get suspended by user-code.
{