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