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