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 <string.h> 25 #include "jvmti.h" 26 #include "agent_common.h" 27 #include "jni_tools.h" 28 #include "jvmti_tools.h" 29 30 extern "C" { 31 32 /* ============================================================================= */ 33 34 /* scaffold objects */ 35 static JNIEnv* jni = NULL; 36 static jvmtiEnv *jvmti = NULL; 37 static jlong timeout = 0; 38 39 /* constants */ 40 #define THREADS_COUNT 6 41 #define EVENTS_COUNT 2 42 #define MAX_NAME_LENGTH 100 43 #define MAX_STACK_SIZE 100 44 45 /* tested events */ 46 static jvmtiEvent eventsList[EVENTS_COUNT] = { 47 JVMTI_EVENT_COMPILED_METHOD_LOAD, 48 JVMTI_EVENT_COMPILED_METHOD_UNLOAD 49 }; 50 51 /* thread description structure */ 52 typedef struct { 53 char threadName[MAX_NAME_LENGTH]; 54 char methodName[MAX_NAME_LENGTH]; 55 char methodSig[MAX_NAME_LENGTH]; 56 int minDepth; 57 jthread thread; 58 jclass cls; 59 jmethodID method; 60 int methodCompiled; 61 } ThreadDesc; 62 63 /* descriptions of tested threads */ 64 static ThreadDesc threadsDesc[THREADS_COUNT] = { 65 {"threadRunning", "testedMethod", "(ZI)V", 2, NULL, NULL, NULL, NSK_FALSE}, 66 {"threadEntering", "testedMethod", "(ZI)V", 2, NULL, NULL, NULL, NSK_FALSE}, 67 {"threadWaiting", "testedMethod", "(ZI)V", 2, NULL, NULL, NULL, NSK_FALSE}, 68 {"threadSleeping", "testedMethod", "(ZI)V", 2, NULL, NULL, NULL, NSK_FALSE}, 69 {"threadRunningInterrupted", "testedMethod", "(ZI)V", 2, NULL, NULL, NULL, NSK_FALSE}, 70 {"threadRunningNative", "testedMethod", "(ZI)V", 2, NULL, NULL, NULL, NSK_FALSE} 71 }; 72 73 /* indexes of known threads */ 74 static const int interruptedThreadIndex = THREADS_COUNT - 2; 75 static const int nativeThreadIndex = THREADS_COUNT - 1; 76 77 /* ============================================================================= */ 78 79 /* testcase(s) */ 80 static int prepare(); 81 static int generateEvents(); 82 static int checkSuspendedThreads(); 83 static int suspendThreadsIndividually(int suspend); 84 static int clean(); 85 86 /* ============================================================================= */ 87 88 /** Agent algorithm. */ 89 static void JNICALL 90 agentProc(jvmtiEnv* jvmti, JNIEnv* agentJNI, void* arg) { 91 jni = agentJNI; 92 93 NSK_DISPLAY0("Wait for debuggee to become ready\n"); 94 if (!nsk_jvmti_waitForSync(timeout)) 95 return; 96 97 { 98 NSK_DISPLAY0("Prepare data\n"); 99 if (!prepare()) { 100 nsk_jvmti_setFailStatus(); 101 return; 102 } 103 104 NSK_DISPLAY0("Generate missed events\n"); 105 if (!generateEvents()) 106 return; 107 108 NSK_DISPLAY0("Suspend each thread\n"); 109 if (!suspendThreadsIndividually(NSK_TRUE)) 110 return; 111 112 NSK_DISPLAY0("Check stack frames of suspended threads\n"); 113 if (!checkSuspendedThreads()) 114 return; 115 116 NSK_DISPLAY0("Resume each thread\n"); 117 if (!suspendThreadsIndividually(NSK_FALSE)) 118 return; 119 120 NSK_DISPLAY0("Clean data\n"); 121 if (!clean()) { 122 nsk_jvmti_setFailStatus(); 123 return; 124 } 125 } 126 127 NSK_DISPLAY0("Let debuggee to finish\n"); 128 if (!nsk_jvmti_resumeSync()) 129 return; 130 } 131 132 /* ============================================================================= */ 133 134 /** 135 * Generate missed events (COMPILED_METHOD_LOAD only). 136 */ 137 static int generateEvents() { 138 if (!NSK_JVMTI_VERIFY( 139 NSK_CPP_STUB2(GenerateEvents, jvmti, JVMTI_EVENT_COMPILED_METHOD_LOAD))) { 140 nsk_jvmti_setFailStatus(); 141 return NSK_FALSE; 142 } 143 return NSK_TRUE; 144 } 145 146 /** 147 * Prepare data. 148 * - clean threads list 149 * - get all live threads 150 * - get threads name 151 * - find tested threads 152 * - make global refs 153 * - enable events 154 */ 155 static int prepare() { 156 jthread *allThreadsList = NULL; 157 jint allThreadsCount = 0; 158 int found = 0; 159 int i; 160 161 NSK_DISPLAY1("Find tested threads: %d\n", THREADS_COUNT); 162 163 /* clean threads list */ 164 for (i = 0; i < THREADS_COUNT; i++) { 165 threadsDesc[i].thread = (jthread)NULL; 166 threadsDesc[i].method = (jmethodID)NULL; 167 threadsDesc[i].methodCompiled = NSK_FALSE; 168 } 169 170 /* get all live threads */ 171 if (!NSK_JVMTI_VERIFY( 172 NSK_CPP_STUB3(GetAllThreads, jvmti, &allThreadsCount, &allThreadsList))) 173 return NSK_FALSE; 174 175 if (!NSK_VERIFY(allThreadsCount > 0 && allThreadsList != NULL)) 176 return NSK_FALSE; 177 178 /* find tested threads */ 179 for (i = 0; i < allThreadsCount; i++) { 180 jvmtiThreadInfo threadInfo; 181 182 if (!NSK_VERIFY(allThreadsList[i] != NULL)) 183 return NSK_FALSE; 184 185 if (!NSK_JVMTI_VERIFY( 186 NSK_CPP_STUB3(GetThreadInfo, jvmti, allThreadsList[i], &threadInfo))) 187 return NSK_FALSE; 188 189 if (threadInfo.name != NULL) { 190 int j; 191 192 for (j = 0; j < THREADS_COUNT; j++) { 193 if (strcmp(threadInfo.name, threadsDesc[j].threadName) == 0) { 194 threadsDesc[j].thread = allThreadsList[i]; 195 NSK_DISPLAY3(" thread #%d (%s): 0x%p\n", 196 j, threadInfo.name, (void*)threadsDesc[j].thread); 197 } 198 } 199 } 200 } 201 202 /* deallocate all threads list */ 203 if (!NSK_JVMTI_VERIFY( 204 NSK_CPP_STUB2(Deallocate, jvmti, (unsigned char*)allThreadsList))) 205 return NSK_FALSE; 206 207 /* check if all tested threads found */ 208 found = 0; 209 for (i = 0; i < THREADS_COUNT; i++) { 210 if (threadsDesc[i].thread == NULL) { 211 NSK_COMPLAIN2("Not found tested thread #%d (%s)\n", i, threadsDesc[i].threadName); 212 } else { 213 found++; 214 } 215 } 216 217 if (found < THREADS_COUNT) 218 return NSK_FALSE; 219 220 /* get threads class and frame method */ 221 NSK_DISPLAY0("Find tested methods:\n"); 222 for (i = 0; i < THREADS_COUNT; i++) { 223 224 if (!NSK_JNI_VERIFY(jni, (threadsDesc[i].cls = 225 NSK_CPP_STUB2(GetObjectClass, jni, threadsDesc[i].thread)) != NULL)) 226 return NSK_FALSE; 227 228 if (!NSK_JNI_VERIFY(jni, (threadsDesc[i].method = 229 NSK_CPP_STUB4(GetMethodID, jni, threadsDesc[i].cls, 230 threadsDesc[i].methodName, threadsDesc[i].methodSig)) != NULL)) 231 return NSK_FALSE; 232 233 NSK_DISPLAY4(" thread #%d (%s): 0x%p (%s)\n", 234 i, threadsDesc[i].threadName, 235 (void*)threadsDesc[i].method, 236 threadsDesc[i].methodName); 237 } 238 239 /* make global refs */ 240 for (i = 0; i < THREADS_COUNT; i++) { 241 if (!NSK_JNI_VERIFY(jni, (threadsDesc[i].thread = (jthread) 242 NSK_CPP_STUB2(NewGlobalRef, jni, threadsDesc[i].thread)) != NULL)) 243 return NSK_FALSE; 244 if (!NSK_JNI_VERIFY(jni, (threadsDesc[i].cls = (jclass) 245 NSK_CPP_STUB2(NewGlobalRef, jni, threadsDesc[i].cls)) != NULL)) 246 return NSK_FALSE; 247 } 248 249 NSK_DISPLAY0("Enable tested events\n"); 250 if (!nsk_jvmti_enableEvents(JVMTI_ENABLE, EVENTS_COUNT, eventsList, NULL)) 251 return NSK_FALSE; 252 253 return NSK_TRUE; 254 } 255 256 /** 257 * Suspend or resume tested threads. 258 */ 259 static int suspendThreadsIndividually(int suspend) { 260 int i; 261 262 for (i = 0; i < THREADS_COUNT; i++) { 263 if (suspend) { 264 NSK_DISPLAY2(" suspend thread #%d (%s)\n", i, threadsDesc[i].threadName); 265 if (!NSK_JVMTI_VERIFY( 266 NSK_CPP_STUB2(SuspendThread, jvmti, threadsDesc[i].thread))) 267 nsk_jvmti_setFailStatus(); 268 } else { 269 NSK_DISPLAY2(" resume thread #%d (%s)\n", i, threadsDesc[i].threadName); 270 if (!NSK_JVMTI_VERIFY( 271 NSK_CPP_STUB2(ResumeThread, jvmti, threadsDesc[i].thread))) 272 nsk_jvmti_setFailStatus(); 273 } 274 } 275 return NSK_TRUE; 276 } 277 278 /** 279 * Testcase: check tested threads. 280 * - invoke getFrameCount() for each thread 281 * - check if frameCount is not less than minimal stack depth 282 * - invoke getStackTrace() for each thread 283 * - check if stack depth is equal to frameCount 284 * 285 * Returns NSK_TRUE if test may continue; or NSK_FALSE for test break. 286 */ 287 static int checkSuspendedThreads() { 288 char kind[256] = ""; 289 int i; 290 291 /* check each thread */ 292 for (i = 0; i < THREADS_COUNT; i++) { 293 jint frameCount = 0; 294 jint frameStackSize = 0; 295 jvmtiFrameInfo frameStack[MAX_STACK_SIZE]; 296 int found = 0; 297 298 /* make proper kind */ 299 strcpy(kind, threadsDesc[i].methodCompiled ? "compiled " : "not compiled "); 300 NSK_DISPLAY2(" thread #%d (%s):\n", i, threadsDesc[i].threadName); 301 302 /* get frame count */ 303 if (!NSK_JVMTI_VERIFY( 304 NSK_CPP_STUB3(GetFrameCount, jvmti, 305 threadsDesc[i].thread, &frameCount))) { 306 nsk_jvmti_setFailStatus(); 307 return NSK_TRUE; 308 } 309 310 NSK_DISPLAY1(" frameCount: %d\n", (int)frameCount); 311 312 /* get stack trace */ 313 if (!NSK_JVMTI_VERIFY( 314 NSK_CPP_STUB6(GetStackTrace, jvmti, threadsDesc[i].thread, 315 0, MAX_STACK_SIZE, frameStack, &frameStackSize))) { 316 nsk_jvmti_setFailStatus(); 317 return NSK_TRUE; 318 } 319 320 NSK_DISPLAY1(" stack depth: %d\n", (int)frameStackSize); 321 322 /* check frame count */ 323 if (frameCount < threadsDesc[i].minDepth) { 324 NSK_COMPLAIN5("Too few frameCount of %s thread #%d (%s):\n" 325 "# got frameCount: %d\n" 326 "# expected minimum: %d\n", 327 kind, i, threadsDesc[i].threadName, 328 (int)frameCount, threadsDesc[i].minDepth); 329 nsk_jvmti_setFailStatus(); 330 } 331 332 if (frameStackSize != frameCount) { 333 NSK_COMPLAIN5("Different frames count for %s thread #%d (%s):\n" 334 "# getStackTrace(): %d\n" 335 "# getFrameCount(): %d\n", 336 kind, i, threadsDesc[i].threadName, 337 (int)frameStackSize, (int)frameCount); 338 nsk_jvmti_setFailStatus(); 339 } 340 341 } 342 343 /* test may continue */ 344 return NSK_TRUE; 345 } 346 347 /** 348 * Clean data. 349 * - disable events 350 * - dispose global references to tested threads 351 */ 352 static int clean() { 353 int i; 354 355 NSK_DISPLAY0("Disable events\n"); 356 if (!nsk_jvmti_enableEvents(JVMTI_DISABLE, EVENTS_COUNT, eventsList, NULL)) 357 return NSK_FALSE; 358 359 NSK_DISPLAY0("Dispose global references to threads\n"); 360 for (i = 0; i < THREADS_COUNT; i++) { 361 NSK_TRACE(NSK_CPP_STUB2(DeleteGlobalRef, jni, threadsDesc[i].thread)); 362 NSK_TRACE(NSK_CPP_STUB2(DeleteGlobalRef, jni, threadsDesc[i].cls)); 363 } 364 365 return NSK_TRUE; 366 } 367 368 /* ============================================================================= */ 369 370 /** 371 * COMPILED_METHOD_LOAD callback. 372 * - turn on flag that method is compiled 373 */ 374 JNIEXPORT void JNICALL 375 callbackCompiledMethodLoad(jvmtiEnv* jvmti, jmethodID method, 376 jint code_size, const void* code_addr, 377 jint map_length, const jvmtiAddrLocationMap* map, 378 const void* compile_info) { 379 int i; 380 381 /* check if event is for tested method and turn flag on */ 382 for (i = 0; i < THREADS_COUNT; i++) { 383 if (threadsDesc[i].method == method) { 384 threadsDesc[i].methodCompiled = NSK_TRUE; 385 386 NSK_DISPLAY2(" COMPILED_METHOD_LOAD for method #%d (%s):\n", 387 i, threadsDesc[i].methodName); 388 NSK_DISPLAY1(" methodID: 0x%p\n", 389 (void*)threadsDesc[i].method); 390 NSK_DISPLAY1(" code_size: %d\n", 391 (int)code_size); 392 NSK_DISPLAY1(" map_length: %d\n", 393 (int)map_length); 394 break; 395 } 396 } 397 } 398 399 /** 400 * COMPILED_METHOD_UNLOAD callback. 401 * - turn off flag that method is compiled 402 */ 403 JNIEXPORT void JNICALL 404 callbackCompiledMethodUnload(jvmtiEnv* jvmti, jmethodID method, 405 const void* code_addr) { 406 int i; 407 408 /* check if event is for tested method and turn flag off */ 409 for (i = 0; i < THREADS_COUNT; i++) { 410 if (threadsDesc[i].method == method) { 411 threadsDesc[i].methodCompiled = NSK_FALSE; 412 413 NSK_DISPLAY2(" COMPILED_METHOD_UNLOAD for method #%d (%s):\n", 414 i, threadsDesc[i].methodName); 415 NSK_DISPLAY1(" methodID: 0x%p\n", 416 (void*)threadsDesc[i].method); 417 break; 418 } 419 } 420 } 421 422 /* ============================================================================= */ 423 424 volatile int testedThreadReady = NSK_FALSE; 425 volatile int testedThreadShouldFinish = NSK_FALSE; 426 427 /** Native running method in tested thread. */ 428 JNIEXPORT void JNICALL 429 Java_nsk_jvmti_scenarios_sampling_SP06_sp06t001ThreadRunningNative_testedMethod(JNIEnv* jni, 430 jobject obj, 431 jboolean simulate, 432 jint i) { 433 if (!simulate) { 434 volatile int k = 0, n = 1000; 435 436 /* run in a continous loop */ 437 testedThreadReady = NSK_TRUE; 438 while (!testedThreadShouldFinish) { 439 if (n <= 0) 440 n = 1000; 441 if (k >= n) 442 k = 0; 443 k++; 444 } 445 } 446 } 447 448 /** Wait for native method is running. */ 449 JNIEXPORT jboolean JNICALL 450 Java_nsk_jvmti_scenarios_sampling_SP06_sp06t001ThreadRunningNative_checkReady(JNIEnv* jni, 451 jobject obj) { 452 while (!testedThreadReady) { 453 nsk_jvmti_sleep(1000); 454 } 455 return testedThreadReady ? JNI_TRUE : JNI_FALSE; 456 } 457 458 /** Let native method to finish. */ 459 JNIEXPORT void JNICALL 460 Java_nsk_jvmti_scenarios_sampling_SP06_sp06t001ThreadRunningNative_letFinish(JNIEnv* jni, 461 jobject obj) { 462 testedThreadShouldFinish = NSK_TRUE; 463 } 464 465 /* ============================================================================= */ 466 467 /** Agent library initialization. */ 468 #ifdef STATIC_BUILD 469 JNIEXPORT jint JNICALL Agent_OnLoad_sp06t001(JavaVM *jvm, char *options, void *reserved) { 470 return Agent_Initialize(jvm, options, reserved); 471 } 472 JNIEXPORT jint JNICALL Agent_OnAttach_sp06t001(JavaVM *jvm, char *options, void *reserved) { 473 return Agent_Initialize(jvm, options, reserved); 474 } 475 JNIEXPORT jint JNI_OnLoad_sp06t001(JavaVM *jvm, char *options, void *reserved) { 476 return JNI_VERSION_1_8; 477 } 478 #endif 479 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 480 481 if (!NSK_VERIFY(nsk_jvmti_parseOptions(options))) 482 return JNI_ERR; 483 484 timeout = nsk_jvmti_getWaitTime() * 60 * 1000; 485 486 if (!NSK_VERIFY((jvmti = 487 nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL)) 488 return JNI_ERR; 489 490 { 491 jvmtiCapabilities caps; 492 memset(&caps, 0, sizeof(caps)); 493 caps.can_suspend = 1; 494 caps.can_generate_compiled_method_load_events = 1; 495 if (!NSK_JVMTI_VERIFY( 496 NSK_CPP_STUB2(AddCapabilities, jvmti, &caps))) 497 return JNI_ERR; 498 } 499 500 { 501 jvmtiEventCallbacks eventCallbacks; 502 memset(&eventCallbacks, 0, sizeof(eventCallbacks)); 503 eventCallbacks.CompiledMethodLoad = callbackCompiledMethodLoad; 504 eventCallbacks.CompiledMethodUnload = callbackCompiledMethodUnload; 505 if (!NSK_JVMTI_VERIFY( 506 NSK_CPP_STUB3(SetEventCallbacks, jvmti, 507 &eventCallbacks, sizeof(eventCallbacks)))) 508 return JNI_ERR; 509 } 510 511 if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL))) 512 return JNI_ERR; 513 514 return JNI_OK; 515 } 516 517 /* ============================================================================= */ 518 519 }