1 /* 2 * Copyright (c) 2003, 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 <stdio.h> 25 #include <string.h> 26 #include <jni.h> 27 #include <jvmti.h> 28 29 #include "jvmti_common.hpp" 30 #include "jvmti_thread.hpp" 31 32 33 extern "C" { 34 35 /* ========================================================================== */ 36 37 /* scaffold objects */ 38 static jvmtiEnv *jvmti = nullptr; 39 static jlong timeout = 0; 40 41 /* test objects */ 42 static jthread expected_thread = nullptr; 43 static jobject expected_object = nullptr; 44 static volatile int eventsCount = 0; 45 46 /* ========================================================================== */ 47 48 void JNICALL 49 MonitorContendedEnter(jvmtiEnv *jvmti, JNIEnv *jni, jthread thr, jobject obj) { 50 51 LOG("MonitorContendedEnter event:\n\tthread: %p, object: %p, expected object: %p\n",thr, obj, expected_object); 52 53 print_thread_info(jvmti, jni, thr); 54 55 if (expected_thread == nullptr) { 56 jni->FatalError("expected_thread is null."); 57 } 58 59 if (expected_object == nullptr) { 60 jni->FatalError("expected_object is null."); 61 } 62 63 /* check if event is for tested thread and for tested object */ 64 if (jni->IsSameObject(expected_thread, thr) && 65 jni->IsSameObject(expected_object, obj)) { 66 eventsCount++; 67 LOG("Increasing eventCount to %d\n", eventsCount); 68 } 69 } 70 71 /* ========================================================================== */ 72 73 static int prepare(JNIEnv* jni) { 74 jvmtiError err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTER, nullptr); 75 if (err != JVMTI_ERROR_NONE) { 76 jni->FatalError("Error enabling JVMTI_EVENT_MONITOR_CONTENDED_ENTER."); 77 } 78 return JNI_TRUE; 79 } 80 81 static int clean() { 82 LOG("Disabling events\n"); 83 /* disable MonitorContendedEnter event */ 84 jvmtiError err = jvmti->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTER, nullptr); 85 if (err != JVMTI_ERROR_NONE) { 86 set_agent_fail_status(); 87 } 88 return JNI_TRUE; 89 } 90 91 /* agent algorithm 92 */ 93 static void JNICALL 94 agentProc(jvmtiEnv *jvmti, JNIEnv *jni, void *arg) { 95 96 /* wait for initial sync */ 97 if (!agent_wait_for_sync(timeout)) { 98 return; 99 } 100 101 if (!prepare(jni)) { 102 set_agent_fail_status(); 103 return; 104 } 105 106 /* clear events count */ 107 eventsCount = 0; 108 109 /* resume debugee to catch MonitorContendedEnter event */ 110 if (!((agent_resume_sync() == JNI_TRUE) && (agent_wait_for_sync(timeout) == JNI_TRUE))) { 111 return; 112 } 113 LOG("Number of MonitorContendedEnter events: %d\n", eventsCount); 114 115 if (eventsCount == 0) { 116 COMPLAIN("No any MonitorContendedEnter event\n"); 117 set_agent_fail_status(); 118 } 119 120 if (!clean()) { 121 set_agent_fail_status(); 122 return; 123 } 124 125 /* resume debugee after last sync */ 126 if (!agent_resume_sync()) 127 return; 128 } 129 130 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 131 jvmtiCapabilities caps; 132 jvmtiEventCallbacks callbacks; 133 jvmtiError err; 134 jint res; 135 136 timeout = 60000; 137 LOG("Timeout: %d msc\n", (int) timeout); 138 139 res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1); 140 if (res != JNI_OK || jvmti == nullptr) { 141 LOG("Wrong result of a valid call to GetEnv!\n"); 142 return JNI_ERR; 143 } 144 145 err = init_agent_data(jvmti, &agent_data); 146 if (err != JVMTI_ERROR_NONE) { 147 return JNI_ERR; 148 } 149 150 memset(&caps, 0, sizeof(jvmtiCapabilities)); 151 caps.can_generate_monitor_events = 1; 152 caps.can_support_virtual_threads = 1; 153 154 err = jvmti->AddCapabilities(&caps); 155 if (err != JVMTI_ERROR_NONE) { 156 LOG("(AddCapabilities) unexpected error: %s (%d)\n", TranslateError(err), err); 157 return JNI_ERR; 158 } 159 160 err = jvmti->GetCapabilities(&caps); 161 if (err != JVMTI_ERROR_NONE) { 162 LOG("(GetCapabilities) unexpected error: %s (%d)\n", TranslateError(err), err); 163 return JNI_ERR; 164 } 165 166 if (!caps.can_generate_monitor_events) { 167 return JNI_ERR; 168 } 169 170 memset(&callbacks, 0, sizeof(callbacks)); 171 callbacks.MonitorContendedEnter = &MonitorContendedEnter; 172 err = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)); 173 if (err != JVMTI_ERROR_NONE) { 174 return JNI_ERR; 175 } 176 177 /* register agent proc and arg */ 178 set_agent_proc(agentProc, nullptr); 179 180 return JNI_OK; 181 } 182 183 JNIEXPORT jint JNICALL Java_mcontenter01_getEventCount(JNIEnv *jni, jobject obj) { 184 return eventsCount; 185 } 186 187 JNIEXPORT void JNICALL Java_mcontenter01_setExpected(JNIEnv *jni, jobject clz, jobject obj, jobject thread) { 188 LOG("Remembering global reference for monitor object is %p\n", obj); 189 /* make object accessible for a long time */ 190 expected_object = jni->NewGlobalRef(obj); 191 if (expected_object == nullptr) { 192 jni->FatalError("Error saving global reference to monitor.\n"); 193 } 194 195 /* make thread accessable for a long time */ 196 expected_thread = jni->NewGlobalRef(thread); 197 if (thread == nullptr) { 198 jni->FatalError("Error saving global reference to thread.\n"); 199 } 200 201 return; 202 } 203 204 JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { 205 return Agent_Initialize(jvm, options, reserved); 206 } 207 208 JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) { 209 return Agent_Initialize(jvm, options, reserved); 210 } 211 }