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 }