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(jvmti->GenerateEvents(JVMTI_EVENT_COMPILED_METHOD_LOAD))) { 139 nsk_jvmti_setFailStatus(); 140 return NSK_FALSE; 141 } 142 return NSK_TRUE; 143 } 144 145 /** 146 * Prepare data. 147 * - clean threads list 148 * - get all live threads 149 * - get threads name 150 * - find tested threads 151 * - make global refs 152 * - enable events 153 */ 154 static int prepare() { 155 jthread *allThreadsList = NULL; 156 jint allThreadsCount = 0; 157 int found = 0; 158 int i; 159 160 NSK_DISPLAY1("Find tested threads: %d\n", THREADS_COUNT); 161 162 /* clean threads list */ 163 for (i = 0; i < THREADS_COUNT; i++) { 164 threadsDesc[i].thread = (jthread)NULL; 165 threadsDesc[i].method = (jmethodID)NULL; 166 threadsDesc[i].methodCompiled = NSK_FALSE; 167 } 168 169 /* get all live threads */ 170 if (!NSK_JVMTI_VERIFY(jvmti->GetAllThreads(&allThreadsCount, &allThreadsList))) 171 return NSK_FALSE; 172 173 if (!NSK_VERIFY(allThreadsCount > 0 && allThreadsList != NULL)) 174 return NSK_FALSE; 175 176 /* find tested threads */ 177 for (i = 0; i < allThreadsCount; i++) { 178 jvmtiThreadInfo threadInfo; 179 180 if (!NSK_VERIFY(allThreadsList[i] != NULL)) 181 return NSK_FALSE; 182 183 if (!NSK_JVMTI_VERIFY(jvmti->GetThreadInfo(allThreadsList[i], &threadInfo))) 184 return NSK_FALSE; 185 186 if (threadInfo.name != NULL) { 187 int j; 188 189 for (j = 0; j < THREADS_COUNT; j++) { 190 if (strcmp(threadInfo.name, threadsDesc[j].threadName) == 0) { 191 threadsDesc[j].thread = allThreadsList[i]; 192 NSK_DISPLAY3(" thread #%d (%s): 0x%p\n", 193 j, threadInfo.name, (void*)threadsDesc[j].thread); 194 } 195 } 196 } 197 } 198 199 /* deallocate all threads list */ 200 if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)allThreadsList))) 201 return NSK_FALSE; 202 203 /* check if all tested threads found */ 204 found = 0; 205 for (i = 0; i < THREADS_COUNT; i++) { 206 if (threadsDesc[i].thread == NULL) { 207 NSK_COMPLAIN2("Not found tested thread #%d (%s)\n", i, threadsDesc[i].threadName); 208 } else { 209 found++; 210 } 211 } 212 213 if (found < THREADS_COUNT) 214 return NSK_FALSE; 215 216 /* get threads class and frame method */ 217 NSK_DISPLAY0("Find tested methods:\n"); 218 for (i = 0; i < THREADS_COUNT; i++) { 219 220 if (!NSK_JNI_VERIFY(jni, (threadsDesc[i].cls = 221 jni->GetObjectClass(threadsDesc[i].thread)) != NULL)) 222 return NSK_FALSE; 223 224 if (!NSK_JNI_VERIFY(jni, (threadsDesc[i].method = 225 jni->GetMethodID(threadsDesc[i].cls, threadsDesc[i].methodName, threadsDesc[i].methodSig)) != NULL)) 226 return NSK_FALSE; 227 228 NSK_DISPLAY4(" thread #%d (%s): 0x%p (%s)\n", 229 i, threadsDesc[i].threadName, 230 (void*)threadsDesc[i].method, 231 threadsDesc[i].methodName); 232 } 233 234 /* make global refs */ 235 for (i = 0; i < THREADS_COUNT; i++) { 236 if (!NSK_JNI_VERIFY(jni, (threadsDesc[i].thread = (jthread) 237 jni->NewGlobalRef(threadsDesc[i].thread)) != NULL)) 238 return NSK_FALSE; 239 if (!NSK_JNI_VERIFY(jni, (threadsDesc[i].cls = (jclass) 240 jni->NewGlobalRef(threadsDesc[i].cls)) != NULL)) 241 return NSK_FALSE; 242 } 243 244 NSK_DISPLAY0("Enable tested events\n"); 245 if (!nsk_jvmti_enableEvents(JVMTI_ENABLE, EVENTS_COUNT, eventsList, NULL)) 246 return NSK_FALSE; 247 248 return NSK_TRUE; 249 } 250 251 /** 252 * Suspend or resume tested threads. 253 */ 254 static int suspendThreadsIndividually(int suspend) { 255 int i; 256 257 for (i = 0; i < THREADS_COUNT; i++) { 258 if (suspend) { 259 NSK_DISPLAY2(" suspend thread #%d (%s)\n", i, threadsDesc[i].threadName); 260 if (!NSK_JVMTI_VERIFY(jvmti->SuspendThread(threadsDesc[i].thread))) 261 nsk_jvmti_setFailStatus(); 262 } else { 263 NSK_DISPLAY2(" resume thread #%d (%s)\n", i, threadsDesc[i].threadName); 264 if (!NSK_JVMTI_VERIFY(jvmti->ResumeThread(threadsDesc[i].thread))) 265 nsk_jvmti_setFailStatus(); 266 } 267 } 268 return NSK_TRUE; 269 } 270 271 /** 272 * Testcase: check tested threads. 273 * - invoke getFrameCount() for each thread 274 * - check if frameCount is not less than minimal stack depth 275 * - invoke getStackTrace() for each thread 276 * - check if stack depth is equal to frameCount 277 * 278 * Returns NSK_TRUE if test may continue; or NSK_FALSE for test break. 279 */ 280 static int checkSuspendedThreads() { 281 char kind[256] = ""; 282 int i; 283 284 /* check each thread */ 285 for (i = 0; i < THREADS_COUNT; i++) { 286 jint frameCount = 0; 287 jint frameStackSize = 0; 288 jvmtiFrameInfo frameStack[MAX_STACK_SIZE]; 289 int found = 0; 290 291 /* make proper kind */ 292 strcpy(kind, threadsDesc[i].methodCompiled ? "compiled " : "not compiled "); 293 NSK_DISPLAY2(" thread #%d (%s):\n", i, threadsDesc[i].threadName); 294 295 /* get frame count */ 296 if (!NSK_JVMTI_VERIFY(jvmti->GetFrameCount(threadsDesc[i].thread, &frameCount))) { 297 nsk_jvmti_setFailStatus(); 298 return NSK_TRUE; 299 } 300 301 NSK_DISPLAY1(" frameCount: %d\n", (int)frameCount); 302 303 /* get stack trace */ 304 if (!NSK_JVMTI_VERIFY( 305 jvmti->GetStackTrace(threadsDesc[i].thread, 0, MAX_STACK_SIZE, frameStack, &frameStackSize))) { 306 nsk_jvmti_setFailStatus(); 307 return NSK_TRUE; 308 } 309 310 NSK_DISPLAY1(" stack depth: %d\n", (int)frameStackSize); 311 312 /* check frame count */ 313 if (frameCount < threadsDesc[i].minDepth) { 314 NSK_COMPLAIN5("Too few frameCount of %s thread #%d (%s):\n" 315 "# got frameCount: %d\n" 316 "# expected minimum: %d\n", 317 kind, i, threadsDesc[i].threadName, 318 (int)frameCount, threadsDesc[i].minDepth); 319 nsk_jvmti_setFailStatus(); 320 } 321 322 if (frameStackSize != frameCount) { 323 NSK_COMPLAIN5("Different frames count for %s thread #%d (%s):\n" 324 "# getStackTrace(): %d\n" 325 "# getFrameCount(): %d\n", 326 kind, i, threadsDesc[i].threadName, 327 (int)frameStackSize, (int)frameCount); 328 nsk_jvmti_setFailStatus(); 329 } 330 331 } 332 333 /* test may continue */ 334 return NSK_TRUE; 335 } 336 337 /** 338 * Clean data. 339 * - disable events 340 * - dispose global references to tested threads 341 */ 342 static int clean() { 343 int i; 344 345 NSK_DISPLAY0("Disable events\n"); 346 if (!nsk_jvmti_enableEvents(JVMTI_DISABLE, EVENTS_COUNT, eventsList, NULL)) 347 return NSK_FALSE; 348 349 NSK_DISPLAY0("Dispose global references to threads\n"); 350 for (i = 0; i < THREADS_COUNT; i++) { 351 NSK_TRACE(jni->DeleteGlobalRef(threadsDesc[i].thread)); 352 NSK_TRACE(jni->DeleteGlobalRef(threadsDesc[i].cls)); 353 } 354 355 return NSK_TRUE; 356 } 357 358 /* ============================================================================= */ 359 360 /** 361 * COMPILED_METHOD_LOAD callback. 362 * - turn on flag that method is compiled 363 */ 364 JNIEXPORT void JNICALL 365 callbackCompiledMethodLoad(jvmtiEnv* jvmti, jmethodID method, 366 jint code_size, const void* code_addr, 367 jint map_length, const jvmtiAddrLocationMap* map, 368 const void* compile_info) { 369 int i; 370 371 /* check if event is for tested method and turn flag on */ 372 for (i = 0; i < THREADS_COUNT; i++) { 373 if (threadsDesc[i].method == method) { 374 threadsDesc[i].methodCompiled = NSK_TRUE; 375 376 NSK_DISPLAY2(" COMPILED_METHOD_LOAD for method #%d (%s):\n", 377 i, threadsDesc[i].methodName); 378 NSK_DISPLAY1(" methodID: 0x%p\n", 379 (void*)threadsDesc[i].method); 380 NSK_DISPLAY1(" code_size: %d\n", 381 (int)code_size); 382 NSK_DISPLAY1(" map_length: %d\n", 383 (int)map_length); 384 break; 385 } 386 } 387 } 388 389 /** 390 * COMPILED_METHOD_UNLOAD callback. 391 * - turn off flag that method is compiled 392 */ 393 JNIEXPORT void JNICALL 394 callbackCompiledMethodUnload(jvmtiEnv* jvmti, jmethodID method, 395 const void* code_addr) { 396 int i; 397 398 /* check if event is for tested method and turn flag off */ 399 for (i = 0; i < THREADS_COUNT; i++) { 400 if (threadsDesc[i].method == method) { 401 threadsDesc[i].methodCompiled = NSK_FALSE; 402 403 NSK_DISPLAY2(" COMPILED_METHOD_UNLOAD for method #%d (%s):\n", 404 i, threadsDesc[i].methodName); 405 NSK_DISPLAY1(" methodID: 0x%p\n", 406 (void*)threadsDesc[i].method); 407 break; 408 } 409 } 410 } 411 412 /* ============================================================================= */ 413 414 volatile int testedThreadReady = NSK_FALSE; 415 volatile int testedThreadShouldFinish = NSK_FALSE; 416 417 /** Native running method in tested thread. */ 418 JNIEXPORT void JNICALL 419 Java_nsk_jvmti_scenarios_sampling_SP06_sp06t001ThreadRunningNative_testedMethod(JNIEnv* jni, 420 jobject obj, 421 jboolean simulate, 422 jint i) { 423 if (!simulate) { 424 volatile int k = 0, n = 1000; 425 426 /* run in a continous loop */ 427 testedThreadReady = NSK_TRUE; 428 while (!testedThreadShouldFinish) { 429 if (n <= 0) 430 n = 1000; 431 if (k >= n) 432 k = 0; 433 k++; 434 } 435 } 436 } 437 438 /** Wait for native method is running. */ 439 JNIEXPORT jboolean JNICALL 440 Java_nsk_jvmti_scenarios_sampling_SP06_sp06t001ThreadRunningNative_checkReady(JNIEnv* jni, 441 jobject obj) { 442 while (!testedThreadReady) { 443 nsk_jvmti_sleep(1000); 444 } 445 return testedThreadReady ? JNI_TRUE : JNI_FALSE; 446 } 447 448 /** Let native method to finish. */ 449 JNIEXPORT void JNICALL 450 Java_nsk_jvmti_scenarios_sampling_SP06_sp06t001ThreadRunningNative_letFinish(JNIEnv* jni, 451 jobject obj) { 452 testedThreadShouldFinish = NSK_TRUE; 453 } 454 455 /* ============================================================================= */ 456 457 /** Agent library initialization. */ 458 #ifdef STATIC_BUILD 459 JNIEXPORT jint JNICALL Agent_OnLoad_sp06t001(JavaVM *jvm, char *options, void *reserved) { 460 return Agent_Initialize(jvm, options, reserved); 461 } 462 JNIEXPORT jint JNICALL Agent_OnAttach_sp06t001(JavaVM *jvm, char *options, void *reserved) { 463 return Agent_Initialize(jvm, options, reserved); 464 } 465 JNIEXPORT jint JNI_OnLoad_sp06t001(JavaVM *jvm, char *options, void *reserved) { 466 return JNI_VERSION_1_8; 467 } 468 #endif 469 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 470 471 if (!NSK_VERIFY(nsk_jvmti_parseOptions(options))) 472 return JNI_ERR; 473 474 timeout = nsk_jvmti_getWaitTime() * 60 * 1000; 475 476 if (!NSK_VERIFY((jvmti = 477 nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL)) 478 return JNI_ERR; 479 480 { 481 jvmtiCapabilities caps; 482 memset(&caps, 0, sizeof(caps)); 483 caps.can_suspend = 1; 484 caps.can_generate_compiled_method_load_events = 1; 485 if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&caps))) 486 return JNI_ERR; 487 } 488 489 { 490 jvmtiEventCallbacks eventCallbacks; 491 memset(&eventCallbacks, 0, sizeof(eventCallbacks)); 492 eventCallbacks.CompiledMethodLoad = callbackCompiledMethodLoad; 493 eventCallbacks.CompiledMethodUnload = callbackCompiledMethodUnload; 494 if (!NSK_JVMTI_VERIFY(jvmti->SetEventCallbacks(&eventCallbacks, sizeof(eventCallbacks)))) 495 return JNI_ERR; 496 } 497 498 if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL))) 499 return JNI_ERR; 500 501 return JNI_OK; 502 } 503 504 /* ============================================================================= */ 505 506 }