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 const int MAX_COUNT = 50; 34 35 /* scaffold objects */ 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 static void check_stack_trace(JNIEnv* env, jthread thr); 45 46 void JNICALL 47 MonitorWaited(jvmtiEnv *jvmti, JNIEnv *jni, jthread thr, jobject obj, jboolean timed_out) { 48 49 LOG("MonitorWaited event:\n\tthread: %p, object: %p, timed_out: %s\n", 50 thr, obj, (timed_out == JNI_TRUE) ? "true" : "false"); 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 if (timed_out == JNI_TRUE) { 67 COMPLAIN("Unexpected timed_out value: true\n"); 68 set_agent_fail_status(); 69 } 70 } 71 72 if (jni->IsVirtualThread(thr)) { 73 check_stack_trace(jni, thr); 74 } 75 } 76 77 /* ========================================================================== */ 78 79 static void check_stack_trace(JNIEnv* jni, jthread thr) { 80 jvmtiError err; 81 jint count = 0; 82 jint skipped = 0; 83 84 print_stack_trace(jvmti, jni, nullptr); 85 86 jvmtiFrameInfo frameInfo[MAX_COUNT]; 87 88 err = jvmti->GetStackTrace(thr, 0, MAX_COUNT, frameInfo, &count); 89 check_jvmti_status(jni, err, "event handler: error in JVMTI GetStackTrace call"); 90 91 const int expected_count = 8; 92 const char* expected_methods[expected_count] = {"wait0", "wait", "run", "runWith", "run", "run", "enter0", "enter"}; 93 94 if (count != expected_count) { 95 LOG("Expected 8 methods in the stack but found %d", count); 96 jni->FatalError("Unexpected method count"); 97 } 98 99 for (int idx = 0; idx < count; idx++) { 100 jclass declaringClass = nullptr; 101 char *clasSignature = nullptr; 102 char *methodName = nullptr; 103 104 err = jvmti->GetMethodName(frameInfo[idx].method, &methodName, nullptr, nullptr); 105 check_jvmti_status(jni, err, "event handler: error in JVMTI GetMethodName call"); 106 107 if (strcmp(methodName, expected_methods[idx]) != 0) { 108 LOG("Expected method %s but found %s", expected_methods[idx], methodName); 109 jni->FatalError("Unexpected method found"); 110 } 111 } 112 } 113 114 static int prepare() { 115 /* enable MonitorWait event */ 116 jvmtiError err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_MONITOR_WAITED, nullptr); 117 if (err != JVMTI_ERROR_NONE) { 118 LOG("Prepare: 11\n"); 119 return JNI_FALSE; 120 } 121 return JNI_TRUE; 122 } 123 124 static int clean() { 125 /* disable MonitorWaited event */ 126 jvmtiError err = jvmti->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_MONITOR_WAITED, nullptr); 127 if (err != JVMTI_ERROR_NONE) { 128 set_agent_fail_status(); 129 } 130 return JNI_TRUE; 131 } 132 133 static void JNICALL 134 agentProc(jvmtiEnv *jvmti, JNIEnv *agentJNI, void *arg) { 135 136 /* wait for initial sync */ 137 if (!agent_wait_for_sync(timeout)) 138 return; 139 140 if (!prepare()) { 141 set_agent_fail_status(); 142 return; 143 } 144 145 /* clear events count */ 146 eventsCount = 0; 147 148 /* resume debugee to catch MonitorWaited event */ 149 if (!((agent_resume_sync() == JNI_TRUE) && (agent_wait_for_sync(timeout) == JNI_TRUE))) { 150 return; 151 } 152 153 LOG("Number of MonitorWaited events: %d\n", eventsCount); 154 155 if (eventsCount == 0) { 156 COMPLAIN("No any MonitorWaited event\n"); 157 set_agent_fail_status(); 158 } 159 160 if (!clean()) { 161 set_agent_fail_status(); 162 return; 163 } 164 165 /* resume debugee after last sync */ 166 if (!agent_resume_sync()) 167 return; 168 } 169 170 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 171 jvmtiCapabilities caps; 172 jvmtiEventCallbacks callbacks; 173 jvmtiError err; 174 jint res; 175 176 timeout = 60000; 177 LOG("Timeout: %d msc\n", (int) timeout); 178 179 res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1); 180 if (res != JNI_OK || jvmti == nullptr) { 181 LOG("Wrong result of a valid call to GetEnv!\n"); 182 return JNI_ERR; 183 } 184 185 err = init_agent_data(jvmti, &agent_data); 186 if (err != JVMTI_ERROR_NONE) { 187 return JNI_ERR; 188 } 189 190 memset(&caps, 0, sizeof(jvmtiCapabilities)); 191 caps.can_generate_monitor_events = 1; 192 caps.can_support_virtual_threads = 1; 193 194 err = jvmti->AddCapabilities(&caps); 195 if (err != JVMTI_ERROR_NONE) { 196 LOG("(AddCapabilities) unexpected error: %s (%d)\n", 197 TranslateError(err), err); 198 return JNI_ERR; 199 } 200 201 err = jvmti->GetCapabilities(&caps); 202 if (err != JVMTI_ERROR_NONE) { 203 LOG("(GetCapabilities) unexpected error: %s (%d)\n", 204 TranslateError(err), err); 205 return JNI_ERR; 206 } 207 208 if (!caps.can_generate_monitor_events) { 209 return JNI_ERR; 210 } 211 212 memset(&callbacks, 0, sizeof(callbacks)); 213 callbacks.MonitorWaited = &MonitorWaited; 214 err = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)); 215 if (err != JVMTI_ERROR_NONE) { 216 return JNI_ERR; 217 } 218 219 /* register agent proc and arg */ 220 set_agent_proc(agentProc, nullptr); 221 222 return JNI_OK; 223 } 224 225 JNIEXPORT void JNICALL Java_monitorwaited01_setExpected(JNIEnv *jni, jobject clz, jobject obj, jobject thread) { 226 LOG("Remembering global reference for monitor object is %p\n", obj); 227 /* make object accessible for a long time */ 228 expected_object = jni->NewGlobalRef(obj); 229 if (expected_object == nullptr) { 230 jni->FatalError("Error saving global reference to monitor.\n"); 231 } 232 233 /* make thread accessable for a long time */ 234 expected_thread = jni->NewGlobalRef(thread); 235 if (thread == nullptr) { 236 jni->FatalError("Error saving global reference to thread.\n"); 237 } 238 239 return; 240 } 241 242 JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { 243 return Agent_Initialize(jvm, options, reserved); 244 } 245 246 JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) { 247 return Agent_Initialize(jvm, options, reserved); 248 } 249 250 }