1 /* 2 * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 #include <cstring> 25 #include <jvmti.h> 26 #include <atomic> 27 #include "jvmti_common.hpp" 28 29 extern "C" { 30 31 static jvmtiEnv *jvmti = nullptr; 32 static std::atomic<int> thread_end_cnt(0); 33 static std::atomic<int> thread_unmount_cnt(0); 34 static std::atomic<int> thread_mount_cnt(0); 35 36 void JNICALL VirtualThreadEnd(jvmtiEnv *jvmti, JNIEnv* jni, jthread vthread) { 37 thread_end_cnt++; 38 } 39 40 void JNICALL VirtualThreadMount(jvmtiEnv* jvmti, ...) { 41 thread_mount_cnt++; 42 } 43 44 void JNICALL VirtualThreadUnmount(jvmtiEnv* jvmti, ...) { 45 thread_unmount_cnt++; 46 } 47 48 JNIEXPORT jint JNICALL 49 Java_VThreadEventTest_threadEndCount(JNIEnv* jni, jclass clazz) { 50 return thread_end_cnt; 51 } 52 53 JNIEXPORT jint JNICALL 54 Java_VThreadEventTest_threadMountCount(JNIEnv* jni, jclass clazz) { 55 return thread_mount_cnt; 56 } 57 58 JNIEXPORT jint JNICALL 59 Java_VThreadEventTest_threadUnmountCount(JNIEnv* jni, jclass clazz) { 60 return thread_unmount_cnt; 61 } 62 63 JNIEXPORT jint JNICALL 64 Agent_OnAttach(JavaVM *vm, char *options, void *reserved) { 65 jvmtiEventCallbacks callbacks; 66 jvmtiCapabilities caps; 67 jvmtiError err; 68 JNIEnv *env; 69 jsize nVMs; 70 jint res; 71 jclass clazz; 72 jmethodID mid; 73 74 LOG("Agent_OnAttach started\n"); 75 if (vm->GetEnv(reinterpret_cast<void **>(&jvmti), JVMTI_VERSION) != JNI_OK || !jvmti) { 76 LOG("Could not initialize JVMTI env\n"); 77 return JNI_ERR; 78 } 79 memset(&caps, 0, sizeof(caps)); 80 caps.can_support_virtual_threads = 1; 81 check_jvmti_error(jvmti->AddCapabilities(&caps), "AddCapabilities"); 82 83 memset(&callbacks, 0, sizeof(callbacks)); 84 callbacks.VirtualThreadEnd = &VirtualThreadEnd; 85 86 err = jvmti->SetEventCallbacks(&callbacks, (jint)sizeof(callbacks)); 87 check_jvmti_error(err, "SetEventCallbacks"); 88 89 err = set_ext_event_callback(jvmti, "VirtualThreadMount", VirtualThreadMount); 90 check_jvmti_error(err, "SetExtEventCallback for VirtualThreadMount"); 91 92 err = set_ext_event_callback(jvmti, "VirtualThreadUnmount", VirtualThreadUnmount); 93 check_jvmti_error(err, "SetExtEventCallback for VirtualThreadUnmount"); 94 95 err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VIRTUAL_THREAD_END, nullptr); 96 check_jvmti_error(err, "SetEventNotificationMode for VirtualThreadEnd"); 97 98 err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, EXT_EVENT_VIRTUAL_THREAD_MOUNT, nullptr); 99 check_jvmti_error(err, "SetEventNotificationMode for VirtualThreadMount"); 100 101 err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, EXT_EVENT_VIRTUAL_THREAD_UNMOUNT, nullptr); 102 check_jvmti_error(err, "SetEventNotificationMode for VirtualThreadUnmount"); 103 104 LOG("vthread events enabled\n"); 105 106 // call VThreadEventTest.agentStarted to notify test that agent has started 107 108 res = JNI_GetCreatedJavaVMs(&vm, 1, &nVMs); 109 if (res != JNI_OK) { 110 LOG("JNI_GetCreatedJavaVMs failed: %d\n", res); 111 return JNI_ERR; 112 } 113 114 res = vm->GetEnv((void **) &env, JNI_VERSION_21); 115 if (res != JNI_OK) { 116 LOG("GetEnv failed: %d\n", res); 117 return JNI_ERR; 118 } 119 120 clazz = env->FindClass("VThreadEventTest"); 121 if (clazz == NULL) { 122 LOG("FindClass failed\n"); 123 return JNI_ERR; 124 } 125 126 mid = env->GetStaticMethodID(clazz, "agentStarted", "()V"); 127 if (mid == NULL) { 128 LOG("GetStaticMethodID failed\n"); 129 return JNI_ERR; 130 } 131 132 env->CallStaticVoidMethod(clazz, mid); 133 if (env->ExceptionOccurred()) { 134 LOG("CallStaticVoidMethod failed\n"); 135 return JNI_ERR; 136 } 137 138 LOG("Agent_OnAttach done\n"); 139 140 return JVMTI_ERROR_NONE; 141 } 142 143 } // extern "C" 144