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