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