1 /* 2 * Copyright (c) 2004, 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 <stdlib.h> 25 #include <string.h> 26 #include "jni_tools.h" 27 #include "agent_common.h" 28 #include "jvmti_tools.h" 29 30 extern "C" { 31 32 /* ========================================================================== */ 33 34 /* scaffold objects */ 35 static jlong timeout = 0; 36 37 /* test objects */ 38 static jthread thread = NULL; 39 static jobject object_M = NULL; 40 /* line numbers of "synchronized (M)" clauses in java part of the test */ 41 static jint lines[] = { 127, 132, 137 }; 42 static volatile int enterEventsCount = 0; 43 static volatile int enteredEventsCount = 0; 44 45 /* ========================================================================== */ 46 47 static jint findLineNumber(jvmtiEnv *jvmti, jthread thread) { 48 jmethodID method = NULL; 49 jlocation location; 50 jvmtiLineNumberEntry* table = NULL; 51 jint count = 0; 52 jint line = 0; 53 int i; 54 55 if (!NSK_JVMTI_VERIFY(jvmti->GetFrameLocation(thread, 0, &method, &location))) 56 return 0; 57 58 if (!NSK_VERIFY(method != NULL)) 59 return 0; 60 61 if (!NSK_VERIFY(location != -1)) 62 return 0; 63 64 if (!NSK_JVMTI_VERIFY(jvmti->GetLineNumberTable(method, &count, &table))) 65 return 0; 66 67 if (!NSK_VERIFY(table != NULL)) 68 return 0; 69 70 if (!NSK_VERIFY(count > 0)) 71 return 0; 72 73 for (i = 0; i < count; i++) { 74 if (location < table[i].start_location) { 75 break; 76 } 77 } 78 79 line = table[i-1].line_number; 80 81 if (table != NULL) { 82 if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)table))) 83 return 0; 84 } 85 86 return line; 87 } 88 89 /* ========================================================================== */ 90 91 void JNICALL 92 MonitorContendedEnter(jvmtiEnv *jvmti, JNIEnv* jni, jthread thr, jobject obj) { 93 jint line = 0; 94 95 if (!NSK_VERIFY(thr != NULL)) { 96 nsk_jvmti_setFailStatus(); 97 NSK_COMPLAIN1("MonitorContendedEnter event: thread=%p\n", thr); 98 return; 99 } 100 101 if (!NSK_VERIFY(obj != NULL)) { 102 nsk_jvmti_setFailStatus(); 103 NSK_COMPLAIN1("MonitorContendedEnter event: object=%p\n", obj); 104 return; 105 } 106 107 /* check if event is for tested thread and object */ 108 if (jni->IsSameObject(thread, thr) && 109 jni->IsSameObject(object_M, obj)) { 110 111 if (!(line = findLineNumber(jvmti, thread))) { 112 nsk_jvmti_setFailStatus(); 113 NSK_COMPLAIN2("MonitorContendedEnter event: thread=%p, object=%p\n", 114 thr, obj); 115 return; 116 } 117 118 NSK_DISPLAY3("MonitorContendedEnter event: thread=%p, object=%p, line=%d\n", 119 thr, obj, line); 120 121 /* workaround of 4527285 bug: in -Xint mode GetFrameLocation 122 returns the location after the monitor enter. 123 */ 124 if (!NSK_VERIFY(line == lines[enterEventsCount] || 125 line == (lines[enterEventsCount] + 1))) { 126 nsk_jvmti_setFailStatus(); 127 NSK_COMPLAIN3("MonitorContendedEnter event: thread=%p, object=%p, line=%d\n", 128 thr, obj, line); 129 } 130 131 enterEventsCount++; 132 } 133 } 134 135 void JNICALL 136 MonitorContendedEntered(jvmtiEnv *jvmti, JNIEnv* jni, jthread thr, jobject obj) { 137 jint line = 0; 138 139 if (!NSK_VERIFY(thr != NULL)) { 140 nsk_jvmti_setFailStatus(); 141 NSK_COMPLAIN1("MonitorContendedEntered event: thread=%p\n", thr); 142 return; 143 } 144 145 if (!NSK_VERIFY(obj != NULL)) { 146 nsk_jvmti_setFailStatus(); 147 NSK_COMPLAIN1("MonitorContendedEntered event: object=%p\n", obj); 148 return; 149 } 150 151 /* check if event is for tested thread and object */ 152 if (jni->IsSameObject(thread, thr) && 153 jni->IsSameObject(object_M, obj)) { 154 155 if (!(line = findLineNumber(jvmti, thread))) { 156 nsk_jvmti_setFailStatus(); 157 NSK_COMPLAIN2("MonitorContendedEntered event: thread=%p, object=%p\n", 158 thr, obj); 159 return; 160 } 161 162 NSK_DISPLAY3("MonitorContendedEntered event: thread=%p, object=%p, line=%d\n", 163 thr, obj, line); 164 165 /* workaround of 4527285 bug: in -Xint mode GetFrameLocation 166 returns the location after the monitor enter. 167 */ 168 if (!NSK_VERIFY(line == lines[enteredEventsCount] || 169 line == (lines[enteredEventsCount] + 1))) { 170 nsk_jvmti_setFailStatus(); 171 NSK_COMPLAIN3("MonitorContendedEntered event: thread=%p, object=%p, line=%d\n", 172 thr, obj, line); 173 } 174 175 enteredEventsCount++; 176 } 177 } 178 179 /* ========================================================================== */ 180 181 static int prepare(jvmtiEnv* jvmti, JNIEnv* jni) { 182 const char* THREAD_NAME = "Debuggee Thread"; 183 const char* FIELD_SIG = "Ljava/lang/Object;"; 184 jvmtiThreadInfo info; 185 jthread *threads = NULL; 186 jint threads_count = 0; 187 jfieldID field = NULL; 188 jclass klass = NULL; 189 int i; 190 191 NSK_DISPLAY0("Prepare: find tested thread\n"); 192 193 /* get all live threads */ 194 if (!NSK_JVMTI_VERIFY(jvmti->GetAllThreads(&threads_count, &threads))) 195 return NSK_FALSE; 196 197 if (!NSK_VERIFY(threads_count > 0 && threads != NULL)) 198 return NSK_FALSE; 199 200 /* find tested thread */ 201 for (i = 0; i < threads_count; i++) { 202 if (!NSK_VERIFY(threads[i] != NULL)) 203 return NSK_FALSE; 204 205 /* get thread information */ 206 if (!NSK_JVMTI_VERIFY(jvmti->GetThreadInfo(threads[i], &info))) 207 return NSK_FALSE; 208 209 NSK_DISPLAY3(" thread #%d (%s): %p\n", i, info.name, threads[i]); 210 211 /* find by name */ 212 if (info.name != NULL && (strcmp(info.name, THREAD_NAME) == 0)) { 213 thread = threads[i]; 214 } 215 216 if (info.name != NULL) { 217 if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)info.name))) 218 return NSK_FALSE; 219 } 220 } 221 222 /* deallocate threads list */ 223 if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)threads))) 224 return NSK_FALSE; 225 226 if (thread == NULL) { 227 NSK_COMPLAIN0("Debuggee thread not found"); 228 return NSK_FALSE; 229 } 230 231 /* make thread accessable for a long time */ 232 if (!NSK_JNI_VERIFY(jni, (thread = jni->NewGlobalRef(thread)) != NULL)) 233 return NSK_FALSE; 234 235 /* get tested thread class */ 236 if (!NSK_JNI_VERIFY(jni, (klass = jni->GetObjectClass(thread)) != NULL)) 237 return NSK_FALSE; 238 239 /* get tested thread field 'M' */ 240 if (!NSK_JNI_VERIFY(jni, (field = jni->GetFieldID(klass, "M", FIELD_SIG)) != NULL)) 241 return NSK_FALSE; 242 243 if (!NSK_JNI_VERIFY(jni, (object_M = jni->GetObjectField(thread, field)) != NULL)) 244 return NSK_FALSE; 245 246 /* make object accessable for a long time */ 247 if (!NSK_JNI_VERIFY(jni, (object_M = jni->NewGlobalRef(object_M)) != NULL)) 248 return NSK_FALSE; 249 250 /* enable MonitorContendedEntered event */ 251 if (!NSK_JVMTI_VERIFY( 252 jvmti->SetEventNotificationMode( 253 JVMTI_ENABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTER, NULL))) 254 return NSK_FALSE; 255 256 /* enable MonitorContendedEntered event */ 257 if (!NSK_JVMTI_VERIFY( 258 jvmti->SetEventNotificationMode( 259 JVMTI_ENABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, NULL))) 260 return NSK_FALSE; 261 262 return NSK_TRUE; 263 } 264 265 static int clean(jvmtiEnv* jvmti, JNIEnv* jni) { 266 267 /* disable MonitorContendedEntered event */ 268 if (!NSK_JVMTI_VERIFY( 269 jvmti->SetEventNotificationMode( 270 JVMTI_DISABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, NULL))) 271 nsk_jvmti_setFailStatus(); 272 273 return NSK_TRUE; 274 } 275 276 /* ========================================================================== */ 277 278 /* agent algorithm */ 279 static void JNICALL 280 agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { 281 282 /* wait for initial sync */ 283 if (!nsk_jvmti_waitForSync(timeout)) 284 return; 285 286 if (!prepare(jvmti, jni)) { 287 nsk_jvmti_setFailStatus(); 288 return; 289 } 290 291 /* resume debugee to catch MonitorContendedEntered events */ 292 if (!(NSK_VERIFY(nsk_jvmti_resumeSync()) && 293 NSK_VERIFY(nsk_jvmti_waitForSync(timeout)))) 294 return; 295 296 NSK_DISPLAY1("Number of MonitorContendedEnter events: %d\n", 297 enterEventsCount); 298 299 if (!(NSK_VERIFY(enterEventsCount == 3))) { 300 nsk_jvmti_setFailStatus(); 301 } 302 303 NSK_DISPLAY1("Number of MonitorContendedEntered events: %d\n", 304 enteredEventsCount); 305 306 if (!(NSK_VERIFY(enteredEventsCount == 3))) { 307 nsk_jvmti_setFailStatus(); 308 } 309 310 if (!clean(jvmti, jni)) { 311 nsk_jvmti_setFailStatus(); 312 return; 313 } 314 315 /* resume debugee after last sync */ 316 if (!nsk_jvmti_resumeSync()) 317 return; 318 } 319 320 /* ========================================================================== */ 321 322 /* agent library initialization */ 323 #ifdef STATIC_BUILD 324 JNIEXPORT jint JNICALL Agent_OnLoad_tc02t001(JavaVM *jvm, char *options, void *reserved) { 325 return Agent_Initialize(jvm, options, reserved); 326 } 327 JNIEXPORT jint JNICALL Agent_OnAttach_tc02t001(JavaVM *jvm, char *options, void *reserved) { 328 return Agent_Initialize(jvm, options, reserved); 329 } 330 JNIEXPORT jint JNI_OnLoad_tc02t001(JavaVM *jvm, char *options, void *reserved) { 331 return JNI_VERSION_1_8; 332 } 333 #endif 334 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 335 jvmtiEnv* jvmti = NULL; 336 jvmtiCapabilities caps; 337 jvmtiEventCallbacks callbacks; 338 339 /* init framework and parse options */ 340 if (!NSK_VERIFY(nsk_jvmti_parseOptions(options))) 341 return JNI_ERR; 342 343 timeout = nsk_jvmti_getWaitTime() * 60000; 344 NSK_DISPLAY1("Timeout: %d msc\n", (int)timeout); 345 346 /* create JVMTI environment */ 347 if (!NSK_VERIFY((jvmti = 348 nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL)) 349 return JNI_ERR; 350 351 /* add capabilities */ 352 memset(&caps, 0, sizeof(caps)); 353 caps.can_generate_monitor_events = 1; 354 caps.can_get_line_numbers = 1; 355 if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&caps))) 356 return JNI_ERR; 357 358 memset(&callbacks, 0, sizeof(callbacks)); 359 callbacks.MonitorContendedEnter = &MonitorContendedEnter; 360 callbacks.MonitorContendedEntered = &MonitorContendedEntered; 361 if (!NSK_JVMTI_VERIFY(jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)))) 362 return JNI_ERR; 363 364 /* register agent proc and arg */ 365 if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL))) 366 return JNI_ERR; 367 368 return JNI_OK; 369 } 370 371 /* ========================================================================== */ 372 373 }