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 69 LOG("Agent_OnAttach started\n"); 70 if (vm->GetEnv(reinterpret_cast<void **>(&jvmti), JVMTI_VERSION) != JNI_OK || !jvmti) { 71 LOG("Could not initialize JVMTI env\n"); 72 return JNI_ERR; 73 } 74 memset(&caps, 0, sizeof(caps)); 75 caps.can_support_virtual_threads = 1; 76 check_jvmti_error(jvmti->AddCapabilities(&caps), "AddCapabilities"); 77 78 memset(&callbacks, 0, sizeof(callbacks)); 79 callbacks.VirtualThreadEnd = &VirtualThreadEnd; 80 81 err = jvmti->SetEventCallbacks(&callbacks, (jint)sizeof(callbacks)); 82 check_jvmti_error(err, "SetEventCallbacks"); 83 84 err = set_ext_event_callback(jvmti, "VirtualThreadMount", VirtualThreadMount); 85 check_jvmti_error(err, "SetExtEventCallback for VirtualThreadMount"); 86 87 err = set_ext_event_callback(jvmti, "VirtualThreadUnmount", VirtualThreadUnmount); 88 check_jvmti_error(err, "SetExtEventCallback for VirtualThreadUnmount"); 89 90 err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VIRTUAL_THREAD_END, nullptr); 91 check_jvmti_error(err, "SetEventNotificationMode for VirtualThreadEnd"); 92 93 err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, EXT_EVENT_VIRTUAL_THREAD_MOUNT, nullptr); 94 check_jvmti_error(err, "SetEventNotificationMode for VirtualThreadMount"); 95 96 err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, EXT_EVENT_VIRTUAL_THREAD_UNMOUNT, nullptr); 97 check_jvmti_error(err, "SetEventNotificationMode for VirtualThreadUnmount"); 98 99 LOG("vthread events enabled\n"); 100 return JVMTI_ERROR_NONE; 101 } 102 103 } // extern "C" 104