1 /*
  2  * Copyright (c) 2003, 2018, 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.h"
 30 #include "jvmti_thread.h"
 31 
 32 
 33 extern "C" {
 34 
 35 /* ========================================================================== */
 36 
 37 /* scaffold objects */
 38 static JNIEnv *jni = NULL;
 39 static jvmtiEnv *jvmti = NULL;
 40 static jlong timeout = 0;
 41 
 42 /* test objects */
 43 static jthread expected_thread = NULL;
 44 static jobject expected_object = NULL;
 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 == NULL) {
 57     jni->FatalError("expected_thread is NULL.");
 58   }
 59 
 60   if (expected_object == NULL) {
 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, NULL);
 76   if (err != JVMTI_ERROR_NONE) {
 77     jni->FatalError("Error enabling JVMTI_EVENT_MONITOR_CONTENDED_ENTER.");
 78   }
 79   return NSK_TRUE;
 80 }
 81 
 82 static int clean() {
 83   jvmtiError err;
 84   LOG("Disabling events\n");
 85   /* disable MonitorContendedEnter event */
 86   err = jvmti->SetEventNotificationMode(JVMTI_DISABLE,
 87                                         JVMTI_EVENT_MONITOR_CONTENDED_ENTER,
 88                                         NULL);
 89   if (err != JVMTI_ERROR_NONE) {
 90     nsk_jvmti_setFailStatus();
 91   }
 92 
 93   jni->DeleteGlobalRef(expected_object);
 94   jni->DeleteGlobalRef(expected_thread);
 95   return NSK_TRUE;
 96 }
 97 
 98 /* ========================================================================== */
 99 
100 /* agent algorithm
101  */
102 static void JNICALL
103 agentProc(jvmtiEnv *jvmti, JNIEnv *agentJNI, void *arg) {
104   jni = agentJNI;
105 
106   /* wait for initial sync */
107   if (!nsk_jvmti_waitForSync(timeout)) {
108     return;
109   }
110 
111   if (!prepare()) {
112     nsk_jvmti_setFailStatus();
113     return;
114   }
115 
116   /* clear events count */
117   eventsCount = 0;
118 
119   /* resume debugee to catch MonitorContendedEnter event */
120   if (!((nsk_jvmti_resumeSync() == NSK_TRUE) && (nsk_jvmti_waitForSync(timeout) ==NSK_TRUE))) {
121     return;
122   }
123   NSK_DISPLAY1("Number of MonitorContendedEnter events: %d\n", eventsCount);
124 
125   if (eventsCount == 0) {
126     NSK_COMPLAIN0("No any MonitorContendedEnter event\n");
127     nsk_jvmti_setFailStatus();
128   }
129 
130   if (!clean()) {
131     nsk_jvmti_setFailStatus();
132     return;
133   }
134 
135 /* resume debugee after last sync */
136   if (!nsk_jvmti_resumeSync())
137     return;
138 }
139 
140 /* ========================================================================== */
141 
142 /* agent library initialization
143  */
144 #ifdef STATIC_BUILD
145 JNIEXPORT jint JNICALL Agent_OnLoad_mcontenter01(JavaVM *jvm, char *options, void *reserved) {
146     return Agent_Initialize(jvm, options, reserved);
147 }
148 JNIEXPORT jint JNICALL Agent_OnAttach_mcontenter01(JavaVM *jvm, char *options, void *reserved) {
149     return Agent_Initialize(jvm, options, reserved);
150 }
151 JNIEXPORT jint JNI_OnLoad_mcontenter01(JavaVM *jvm, char *options, void *reserved) {
152     return JNI_VERSION_1_8;
153 }
154 #endif
155 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
156   jvmtiCapabilities caps;
157   jvmtiEventCallbacks callbacks;
158   jvmtiError err;
159   jint res;
160 
161   timeout = 60000; //TODO fix
162   NSK_DISPLAY1("Timeout: %d msc\n", (int) timeout);
163 
164   res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1);
165   if (res != JNI_OK || jvmti == NULL) {
166     LOG("Wrong result of a valid call to GetEnv!\n");
167     return JNI_ERR;
168   }
169 
170   err = init_agent_data(jvmti, &agent_data);
171   if (err != JVMTI_ERROR_NONE) {
172     return JNI_ERR;
173   }
174 
175   memset(&caps, 0, sizeof(jvmtiCapabilities));
176   caps.can_generate_monitor_events = 1;
177   caps.can_support_virtual_threads = 1;
178 
179   err = jvmti->AddCapabilities(&caps);
180   if (err != JVMTI_ERROR_NONE) {
181     LOG("(AddCapabilities) unexpected error: %s (%d)\n", TranslateError(err), err);
182     return JNI_ERR;
183   }
184 
185   err = jvmti->GetCapabilities(&caps);
186   if (err != JVMTI_ERROR_NONE) {
187     LOG("(GetCapabilities) unexpected error: %s (%d)\n", TranslateError(err), err);
188     return JNI_ERR;
189   }
190 
191   if (!caps.can_generate_monitor_events) {
192     return JNI_ERR;
193   }
194 
195   memset(&callbacks, 0, sizeof(callbacks));
196   callbacks.MonitorContendedEnter = &MonitorContendedEnter;
197   err = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks));
198   if (err != JVMTI_ERROR_NONE) {
199     return JNI_ERR;
200   }
201 
202   /* register agent proc and arg */
203   nsk_jvmti_setAgentProc(agentProc, NULL);
204 
205   return JNI_OK;
206 }
207 
208 JNIEXPORT jint JNICALL Java_mcontenter01_getEventCount(JNIEnv *jni, jobject obj) {
209   return eventsCount;
210 }
211 
212 JNIEXPORT void JNICALL Java_mcontenter01_setExpected(JNIEnv *jni, jobject clz, jobject obj, jobject thread) {
213   LOG("Remembering global reference for monitor object is %p\n", obj);
214   /* make object accessible for a long time */
215   expected_object = jni->NewGlobalRef(obj);
216   if (expected_object == NULL) {
217     jni->FatalError("Error saving global reference to monitor.\n");
218   }
219 
220   /* make thread accessable for a long time */
221   expected_thread = jni->NewGlobalRef(thread);
222   if (thread == NULL) {
223     jni->FatalError("Error saving global reference to thread.\n");
224   }
225 
226   return;
227 }
228 
229 
230 JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
231   return Agent_Initialize(jvm, options, reserved);
232 }
233 
234 JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
235   return Agent_Initialize(jvm, options, reserved);
236 }
237 }