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