ART: Add ThreadStart & ThreadEnd
Add support for ThreadStart and ThreadEnd events. Add tests.
Bug: 31684920
Test: m test-art-host-run-test-924-threads
Change-Id: I516993402747ffdc9a7d66985b21b95c059be107
diff --git a/test/924-threads/expected.txt b/test/924-threads/expected.txt
index 3b7fb24..67d20eb 100644
--- a/test/924-threads/expected.txt
+++ b/test/924-threads/expected.txt
@@ -31,3 +31,7 @@
[Thread[FinalizerDaemon,5,system], Thread[FinalizerWatchdogDaemon,5,system], Thread[HeapTaskDaemon,5,system], Thread[ReferenceQueueDaemon,5,system], Thread[Signal Catcher,5,system], Thread[main,5,main]]
JVMTI_ERROR_THREAD_NOT_ALIVE
JVMTI_ERROR_THREAD_NOT_ALIVE
+Constructed thread
+Thread(EventTestThread): start
+Thread(EventTestThread): end
+Thread joined
diff --git a/test/924-threads/src/Main.java b/test/924-threads/src/Main.java
index 58695f7..29c4aa3 100644
--- a/test/924-threads/src/Main.java
+++ b/test/924-threads/src/Main.java
@@ -56,6 +56,8 @@
doAllThreadsTests();
doTLSTests();
+
+ doTestEvents();
}
private static class Holder {
@@ -226,6 +228,22 @@
}
}
+ private static void doTestEvents() throws Exception {
+ enableThreadEvents(true);
+
+ Thread t = new Thread("EventTestThread");
+
+ System.out.println("Constructed thread");
+ Thread.yield();
+
+ t.start();
+ t.join();
+
+ System.out.println("Thread joined");
+
+ enableThreadEvents(false);
+ }
+
private final static Comparator<Thread> THREAD_COMP = new Comparator<Thread>() {
public int compare(Thread o1, Thread o2) {
return o1.getName().compareTo(o2.getName());
@@ -293,4 +311,5 @@
private static native Thread[] getAllThreads();
private static native void setTLS(Thread t, long l);
private static native long getTLS(Thread t);
+ private static native void enableThreadEvents(boolean b);
}
diff --git a/test/924-threads/threads.cc b/test/924-threads/threads.cc
index d35eaa8..0380433 100644
--- a/test/924-threads/threads.cc
+++ b/test/924-threads/threads.cc
@@ -137,5 +137,71 @@
JvmtiErrorToException(env, result);
}
+static void JNICALL ThreadEvent(jvmtiEnv* jvmti_env,
+ JNIEnv* jni_env,
+ jthread thread,
+ bool is_start) {
+ jvmtiThreadInfo info;
+ jvmtiError result = jvmti_env->GetThreadInfo(thread, &info);
+ if (result != JVMTI_ERROR_NONE) {
+ printf("Error getting thread info");
+ return;
+ }
+ printf("Thread(%s): %s\n", info.name, is_start ? "start" : "end");
+
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(info.name));
+ jni_env->DeleteLocalRef(info.thread_group);
+ jni_env->DeleteLocalRef(info.context_class_loader);
+}
+
+static void JNICALL ThreadStart(jvmtiEnv* jvmti_env,
+ JNIEnv* jni_env,
+ jthread thread) {
+ ThreadEvent(jvmti_env, jni_env, thread, true);
+}
+
+static void JNICALL ThreadEnd(jvmtiEnv* jvmti_env,
+ JNIEnv* jni_env,
+ jthread thread) {
+ ThreadEvent(jvmti_env, jni_env, thread, false);
+}
+
+extern "C" JNIEXPORT void JNICALL Java_Main_enableThreadEvents(
+ JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jboolean b) {
+ if (b == JNI_FALSE) {
+ jvmtiError ret = jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
+ JVMTI_EVENT_THREAD_START,
+ nullptr);
+ if (JvmtiErrorToException(env, ret)) {
+ return;
+ }
+ ret = jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
+ JVMTI_EVENT_THREAD_END,
+ nullptr);
+ JvmtiErrorToException(env, ret);
+ return;
+ }
+
+ jvmtiEventCallbacks callbacks;
+ memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
+ callbacks.ThreadStart = ThreadStart;
+ callbacks.ThreadEnd = ThreadEnd;
+ jvmtiError ret = jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
+ if (JvmtiErrorToException(env, ret)) {
+ return;
+ }
+
+ ret = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
+ JVMTI_EVENT_THREAD_START,
+ nullptr);
+ if (JvmtiErrorToException(env, ret)) {
+ return;
+ }
+ ret = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
+ JVMTI_EVENT_THREAD_END,
+ nullptr);
+ JvmtiErrorToException(env, ret);
+}
+
} // namespace Test924Threads
} // namespace art