Implement JVMTI can_signal_thread capability.

Implements the JVMTI can_signal_thread capability and all associated
methods and behaviors. This includes both the StopThread and
InterruptThread functions.

This CL contains the tests for the previous CL.

Test: ./test.py --host -j50
Test: stress --cpu 59 && while ./test/run-test --host 1934; do; done

Bug: 62821960
Bug: 34415266
Change-Id: I7b6fc37da0d2673caa993e486f078cf129d74c0f
diff --git a/openjdkjvmti/OpenjdkJvmTi.cc b/openjdkjvmti/OpenjdkJvmTi.cc
index bac57f9..b30d45a 100644
--- a/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/openjdkjvmti/OpenjdkJvmTi.cc
@@ -163,18 +163,16 @@
     return ThreadUtil::ResumeThreadList(env, request_count, request_list, results);
   }
 
-  static jvmtiError StopThread(jvmtiEnv* env,
-                               jthread thread ATTRIBUTE_UNUSED,
-                               jobject exception ATTRIBUTE_UNUSED) {
+  static jvmtiError StopThread(jvmtiEnv* env, jthread thread, jobject exception) {
     ENSURE_VALID_ENV(env);
     ENSURE_HAS_CAP(env, can_signal_thread);
-    return ERR(NOT_IMPLEMENTED);
+    return ThreadUtil::StopThread(env, thread, exception);
   }
 
-  static jvmtiError InterruptThread(jvmtiEnv* env, jthread thread ATTRIBUTE_UNUSED) {
+  static jvmtiError InterruptThread(jvmtiEnv* env, jthread thread) {
     ENSURE_VALID_ENV(env);
     ENSURE_HAS_CAP(env, can_signal_thread);
-    return ERR(NOT_IMPLEMENTED);
+    return ThreadUtil::InterruptThread(env, thread);
   }
 
   static jvmtiError GetThreadInfo(jvmtiEnv* env, jthread thread, jvmtiThreadInfo* info_ptr) {
diff --git a/openjdkjvmti/art_jvmti.h b/openjdkjvmti/art_jvmti.h
index 10ddfc1..ad405e8 100644
--- a/openjdkjvmti/art_jvmti.h
+++ b/openjdkjvmti/art_jvmti.h
@@ -229,7 +229,7 @@
     .can_get_monitor_info                            = 1,
     .can_pop_frame                                   = 0,
     .can_redefine_classes                            = 1,
-    .can_signal_thread                               = 0,
+    .can_signal_thread                               = 1,
     .can_get_source_file_name                        = 1,
     .can_get_line_numbers                            = 1,
     .can_get_source_debug_extension                  = 1,
diff --git a/openjdkjvmti/ti_thread.cc b/openjdkjvmti/ti_thread.cc
index 907b515..9a809df 100644
--- a/openjdkjvmti/ti_thread.cc
+++ b/openjdkjvmti/ti_thread.cc
@@ -949,4 +949,65 @@
   return OK;
 }
 
+jvmtiError ThreadUtil::StopThread(jvmtiEnv* env ATTRIBUTE_UNUSED,
+                                  jthread thread,
+                                  jobject exception) {
+  art::Thread* self = art::Thread::Current();
+  art::ScopedObjectAccess soa(self);
+  art::StackHandleScope<1> hs(self);
+  if (exception == nullptr) {
+    return ERR(INVALID_OBJECT);
+  }
+  art::ObjPtr<art::mirror::Object> obj(soa.Decode<art::mirror::Object>(exception));
+  if (!obj->GetClass()->IsThrowableClass()) {
+    return ERR(INVALID_OBJECT);
+  }
+  art::Handle<art::mirror::Throwable> exc(hs.NewHandle(obj->AsThrowable()));
+  art::MutexLock tll_mu(self, *art::Locks::thread_list_lock_);
+  art::Thread* target = nullptr;
+  jvmtiError err = ERR(INTERNAL);
+  if (!GetAliveNativeThread(thread, soa, &target, &err)) {
+    return err;
+  } else if (target->GetState() == art::ThreadState::kStarting || target->IsStillStarting()) {
+    return ERR(THREAD_NOT_ALIVE);
+  }
+  struct StopThreadClosure : public art::Closure {
+   public:
+    explicit StopThreadClosure(art::Handle<art::mirror::Throwable> except) : exception_(except) { }
+
+    void Run(art::Thread* me) REQUIRES_SHARED(art::Locks::mutator_lock_) {
+      // Make sure the thread is prepared to notice the exception.
+      art::Runtime::Current()->GetInstrumentation()->InstrumentThreadStack(me);
+      me->SetAsyncException(exception_.Get());
+      // Wake up the thread if it is sleeping.
+      me->Notify();
+    }
+
+   private:
+    art::Handle<art::mirror::Throwable> exception_;
+  };
+  StopThreadClosure c(exc);
+  if (target->RequestSynchronousCheckpoint(&c)) {
+    return OK;
+  } else {
+    // Something went wrong, probably the thread died.
+    return ERR(THREAD_NOT_ALIVE);
+  }
+}
+
+jvmtiError ThreadUtil::InterruptThread(jvmtiEnv* env ATTRIBUTE_UNUSED, jthread thread) {
+  art::Thread* self = art::Thread::Current();
+  art::ScopedObjectAccess soa(self);
+  art::MutexLock tll_mu(self, *art::Locks::thread_list_lock_);
+  art::Thread* target = nullptr;
+  jvmtiError err = ERR(INTERNAL);
+  if (!GetAliveNativeThread(thread, soa, &target, &err)) {
+    return err;
+  } else if (target->GetState() == art::ThreadState::kStarting || target->IsStillStarting()) {
+    return ERR(THREAD_NOT_ALIVE);
+  }
+  target->Interrupt(self);
+  return OK;
+}
+
 }  // namespace openjdkjvmti
diff --git a/openjdkjvmti/ti_thread.h b/openjdkjvmti/ti_thread.h
index ceebff6..09b4cab 100644
--- a/openjdkjvmti/ti_thread.h
+++ b/openjdkjvmti/ti_thread.h
@@ -93,6 +93,9 @@
                                      const jthread* threads,
                                      jvmtiError* results);
 
+  static jvmtiError StopThread(jvmtiEnv* env, jthread thr, jobject exception);
+  static jvmtiError InterruptThread(jvmtiEnv* env, jthread thr);
+
   // Returns true if we decoded the thread and it is alive, false otherwise with an appropriate
   // error placed into 'err'. A thread is alive if it has had it's 'start' function called and has
   // (or at least could have) executed managed code and has not yet returned past it's first managed