Add Jvmti Suspend/ResumeThread functions
Enable the can_suspend jvmti capability and implement all required
functionality associated with it.
Test: ./test.py --host -j40
Bug: 34415266
Bug: 62821960
Bug: 63579748
Change-Id: I83b92de7f81622e1658114b034918e8295805b6e
diff --git a/runtime/openjdkjvmti/ti_thread.h b/runtime/openjdkjvmti/ti_thread.h
index 939aea7..57967eb 100644
--- a/runtime/openjdkjvmti/ti_thread.h
+++ b/runtime/openjdkjvmti/ti_thread.h
@@ -35,8 +35,11 @@
#include "jni.h"
#include "jvmti.h"
+#include "base/mutex.h"
+
namespace art {
class ArtField;
+class Thread;
} // namespace art
namespace openjdkjvmti {
@@ -68,7 +71,33 @@
const void* arg,
jint priority);
+ static jvmtiError SuspendThread(jvmtiEnv* env, jthread thread);
+ static jvmtiError ResumeThread(jvmtiEnv* env, jthread thread);
+
+ static jvmtiError SuspendThreadList(jvmtiEnv* env,
+ jint request_count,
+ const jthread* threads,
+ jvmtiError* results);
+ static jvmtiError ResumeThreadList(jvmtiEnv* env,
+ jint request_count,
+ const jthread* threads,
+ jvmtiError* results);
+
private:
+ // We need to make sure only one thread tries to suspend threads at a time so we can get the
+ // 'suspend-only-once' behavior the spec requires. Internally, ART considers suspension to be a
+ // counted state, allowing a single thread to be suspended multiple times by different users. This
+ // makes mapping into the JVMTI idea of thread suspension difficult. We have decided to split the
+ // difference and ensure that JVMTI tries to treat suspension as the boolean flag as much as
+ // possible with the suspend/resume methods but only do best effort. On the other hand
+ // GetThreadState will be totally accurate as much as possible. This means that calling
+ // ResumeThread on a thread that has state JVMTI_THREAD_STATE_SUSPENDED will not necessarily
+ // cause the thread to wake up if the thread is suspended for the debugger or gc or something.
+ static jvmtiError SuspendSelf(art::Thread* self)
+ REQUIRES(!art::Locks::mutator_lock_, !art::Locks::user_code_suspension_lock_);
+ static jvmtiError SuspendOther(art::Thread* self, jthread target_jthread, art::Thread* target)
+ REQUIRES(!art::Locks::mutator_lock_, !art::Locks::user_code_suspension_lock_);
+
static art::ArtField* context_class_loader_;
};