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 MAX_NAME_LENGTH 100 42 #define MAX_STACK_SIZE 100 43 44 /* thread description structure */ 45 typedef struct { 46 char threadName[MAX_NAME_LENGTH]; 47 char methodName[MAX_NAME_LENGTH]; 48 char methodSig[MAX_NAME_LENGTH]; 49 jthread thread; 50 jclass cls; 51 jmethodID method; 52 jlocation location; 53 } ThreadDesc; 54 55 /* descriptions of tested threads */ 56 static ThreadDesc threadsDesc[THREADS_COUNT] = { 57 {"threadRunning", "testedMethod", "()V", NULL, NULL, NULL, NSK_JVMTI_INVALID_JLOCATION}, 58 {"threadEntering", "testedMethod", "()V", NULL, NULL, NULL, NSK_JVMTI_INVALID_JLOCATION}, 59 {"threadWaiting", "testedMethod", "()V", NULL, NULL, NULL, NSK_JVMTI_INVALID_JLOCATION}, 60 {"threadSleeping", "testedMethod", "()V", NULL, NULL, NULL, NSK_JVMTI_INVALID_JLOCATION}, 61 {"threadRunningInterrupted", "testedMethod", "()V", NULL, NULL, NULL, NSK_JVMTI_INVALID_JLOCATION}, 62 {"threadRunningNative", "testedMethod", "()V", NULL, NULL, NULL, NSK_JVMTI_INVALID_JLOCATION} 63 }; 64 65 /* indexes of known threads */ 66 static const int interruptedThreadIndex = THREADS_COUNT - 2; 67 static const int nativeThreadIndex = THREADS_COUNT - 1; 68 69 /* ============================================================================= */ 70 71 /* testcase(s) */ 72 static int prepare(); 73 static int checkThreads(int suspended, const char* kind); 74 static int suspendThreadsIndividually(int suspend); 75 static int clean(); 76 77 /* ============================================================================= */ 78 79 /** Agent algorithm. */ 80 static void JNICALL 81 agentProc(jvmtiEnv* jvmti, JNIEnv* agentJNI, void* arg) { 82 jni = agentJNI; 83 84 /* wait for initial sync */ 85 if (!nsk_jvmti_waitForSync(timeout)) 86 return; 87 88 /* perform testcase(s) */ 89 { 90 /* prepare data: find threads */ 91 NSK_DISPLAY0("Prepare data\n"); 92 if (!prepare()) { 93 nsk_jvmti_setFailStatus(); 94 return; 95 } 96 97 /* testcase #1: check not suspended threads */ 98 NSK_DISPLAY0("Testcase #1: check stack frames of not suspended threads\n"); 99 if (!checkThreads(NSK_FALSE, "not suspended")) 100 return; 101 102 /* suspend threads */ 103 NSK_DISPLAY0("Suspend each thread\n"); 104 if (!suspendThreadsIndividually(NSK_TRUE)) 105 return; 106 107 /* testcase #2: check suspended threads */ 108 NSK_DISPLAY0("Testcase #2: check stack frames of suspended threads\n"); 109 if (!checkThreads(NSK_TRUE, "suspended")) 110 return; 111 112 /* resume threads */ 113 NSK_DISPLAY0("Resume each thread\n"); 114 if (!suspendThreadsIndividually(NSK_FALSE)) 115 return; 116 117 /* testcase #3: check resumed threads */ 118 NSK_DISPLAY0("Testcase #3: check stack frames of resumed threads\n"); 119 if (!checkThreads(NSK_FALSE, "resumed")) 120 return; 121 122 /* clean date: delete threads references */ 123 NSK_DISPLAY0("Clean data\n"); 124 if (!clean()) { 125 nsk_jvmti_setFailStatus(); 126 return; 127 } 128 } 129 130 /* resume debugee after last sync */ 131 if (!nsk_jvmti_resumeSync()) 132 return; 133 } 134 135 /* ============================================================================= */ 136 137 /** 138 * Prepare data: 139 * - clean threads list 140 * - get all live threads 141 * - get threads name 142 * - find tested threads 143 * - find tested methos 144 * - make global refs 145 */ 146 static int prepare() { 147 jthread *allThreadsList = NULL; 148 jint allThreadsCount = 0; 149 int found = 0; 150 int i; 151 152 NSK_DISPLAY1("Find tested threads: %d\n", THREADS_COUNT); 153 154 /* clean threads list */ 155 for (i = 0; i < THREADS_COUNT; i++) { 156 threadsDesc[i].thread = (jthread)NULL; 157 threadsDesc[i].method = (jmethodID)NULL; 158 threadsDesc[i].location = NSK_JVMTI_INVALID_JLOCATION; 159 } 160 161 /* get all live threads */ 162 if (!NSK_JVMTI_VERIFY( 163 NSK_CPP_STUB3(GetAllThreads, jvmti, &allThreadsCount, &allThreadsList))) 164 return NSK_FALSE; 165 166 if (!NSK_VERIFY(allThreadsCount > 0 && allThreadsList != NULL)) 167 return NSK_FALSE; 168 169 /* find tested threads */ 170 for (i = 0; i < allThreadsCount; i++) { 171 jvmtiThreadInfo threadInfo; 172 173 if (!NSK_VERIFY(allThreadsList[i] != NULL)) 174 return NSK_FALSE; 175 176 /* get thread name (info) */ 177 if (!NSK_JVMTI_VERIFY( 178 NSK_CPP_STUB3(GetThreadInfo, jvmti, allThreadsList[i], &threadInfo))) 179 return NSK_FALSE; 180 181 /* find by name */ 182 if (threadInfo.name != NULL) { 183 int j; 184 185 for (j = 0; j < THREADS_COUNT; j++) { 186 if (strcmp(threadInfo.name, threadsDesc[j].threadName) == 0) { 187 threadsDesc[j].thread = allThreadsList[i]; 188 NSK_DISPLAY3(" thread #%d (%s): %p\n", 189 j, threadInfo.name, (void*)threadsDesc[j].thread); 190 } 191 } 192 } 193 } 194 195 /* deallocate all threads list */ 196 if (!NSK_JVMTI_VERIFY( 197 NSK_CPP_STUB2(Deallocate, jvmti, (unsigned char*)allThreadsList))) 198 return NSK_FALSE; 199 200 /* check if all tested threads found */ 201 found = 0; 202 for (i = 0; i < THREADS_COUNT; i++) { 203 if (threadsDesc[i].thread == NULL) { 204 NSK_COMPLAIN2("Not found tested thread #%d (%s)\n", i, threadsDesc[i].threadName); 205 } else { 206 found++; 207 } 208 } 209 210 if (found < THREADS_COUNT) 211 return NSK_FALSE; 212 213 /* get threads class and frame method */ 214 NSK_DISPLAY0("Find tested methods:\n"); 215 for (i = 0; i < THREADS_COUNT; i++) { 216 /* get thread class */ 217 if (!NSK_JNI_VERIFY(jni, (threadsDesc[i].cls = 218 NSK_CPP_STUB2(GetObjectClass, jni, threadsDesc[i].thread)) != NULL)) 219 return NSK_FALSE; 220 /* get frame method */ 221 if (!NSK_JNI_VERIFY(jni, (threadsDesc[i].method = 222 NSK_CPP_STUB4(GetMethodID, jni, threadsDesc[i].cls, 223 threadsDesc[i].methodName, threadsDesc[i].methodSig)) != NULL)) 224 return NSK_FALSE; 225 226 NSK_DISPLAY4(" thread #%d (%s): %p (%s)\n", 227 i, threadsDesc[i].threadName, 228 (void*)threadsDesc[i].method, 229 threadsDesc[i].methodName); 230 } 231 232 /* make global refs */ 233 for (i = 0; i < THREADS_COUNT; i++) { 234 if (!NSK_JNI_VERIFY(jni, (threadsDesc[i].thread = (jthread) 235 NSK_CPP_STUB2(NewGlobalRef, jni, threadsDesc[i].thread)) != NULL)) 236 return NSK_FALSE; 237 if (!NSK_JNI_VERIFY(jni, (threadsDesc[i].cls = (jclass) 238 NSK_CPP_STUB2(NewGlobalRef, jni, threadsDesc[i].cls)) != NULL)) 239 return NSK_FALSE; 240 } 241 242 return NSK_TRUE; 243 } 244 245 /** 246 * Suspend or resume tested threads. 247 */ 248 static int suspendThreadsIndividually(int suspend) { 249 int i; 250 251 for (i = 0; i < THREADS_COUNT; i++) { 252 if (suspend) { 253 NSK_DISPLAY2(" suspend thread #%d (%s)\n", i, threadsDesc[i].threadName); 254 if (!NSK_JVMTI_VERIFY( 255 NSK_CPP_STUB2(SuspendThread, jvmti, threadsDesc[i].thread))) 256 nsk_jvmti_setFailStatus(); 257 } else { 258 NSK_DISPLAY2(" resume thread #%d (%s)\n", i, threadsDesc[i].threadName); 259 if (!NSK_JVMTI_VERIFY( 260 NSK_CPP_STUB2(ResumeThread, jvmti, threadsDesc[i].thread))) 261 nsk_jvmti_setFailStatus(); 262 } 263 } 264 return NSK_TRUE; 265 } 266 267 /** 268 * Testcase: check tested threads 269 * - call GetFrameCount() and then GetStackTrace() 270 * - for each stack frame of common depth GetFrameLocation() 271 * - compare frame ifno returned by GetFrameLocation() and GetStackTrace() 272 * - find expected frame for tested method 273 * 274 * Returns NSK_TRUE if test may continue; or NSK_FALSE for test break. 275 */ 276 static int checkThreads(int suspended, const char* kind) { 277 int i; 278 279 /* check each thread */ 280 for (i = 0; i < THREADS_COUNT; i++) { 281 jint frameCount = 0; 282 jint frameStackSize = 0; 283 jvmtiFrameInfo frameStack[MAX_STACK_SIZE]; 284 int commonDepth = 0; 285 int found = 0; 286 int j; 287 288 NSK_DISPLAY2(" thread #%d (%s):\n", i, threadsDesc[i].threadName); 289 290 /* get frame count */ 291 if (!NSK_JVMTI_VERIFY( 292 NSK_CPP_STUB3(GetFrameCount, jvmti, 293 threadsDesc[i].thread, &frameCount))) { 294 nsk_jvmti_setFailStatus(); 295 return NSK_TRUE; 296 } 297 NSK_DISPLAY1(" frameCount: %d\n", (int)frameCount); 298 299 /* get stack trace */ 300 if (!NSK_JVMTI_VERIFY( 301 NSK_CPP_STUB6(GetStackTrace, jvmti, threadsDesc[i].thread, 302 0, MAX_STACK_SIZE, frameStack, &frameStackSize))) { 303 nsk_jvmti_setFailStatus(); 304 return NSK_TRUE; 305 } 306 NSK_DISPLAY1(" stack depth: %d\n", (int)frameStackSize); 307 308 commonDepth = (frameCount < frameStackSize ? frameCount : frameStackSize); 309 NSK_DISPLAY1(" common: %d\n", (int)commonDepth); 310 311 /* check first commonDepth frames and find expected method there */ 312 found = 0; 313 for (j = 0; j < commonDepth; j++) { 314 jmethodID qMethod = (jmethodID)NULL; 315 jlocation qLocation = NSK_JVMTI_INVALID_JLOCATION; 316 317 NSK_DISPLAY3(" %d frame: method: %p, location: %ld\n", 318 j, (void*)frameStack[j].method, 319 (long)frameStack[j].location); 320 /* query frame location */ 321 if (!NSK_JVMTI_VERIFY( 322 NSK_CPP_STUB5(GetFrameLocation, jvmti, threadsDesc[i].thread, 323 j, &qMethod, &qLocation))) { 324 nsk_jvmti_setFailStatus(); 325 continue; 326 } 327 328 NSK_DISPLAY2(" queried: method: %p, location: %ld\n", 329 (void*)qMethod, (long)qLocation); 330 331 /* check frame equalaty */ 332 if (frameStack[j].method != qMethod) { 333 NSK_COMPLAIN6("Different method in stack frame #%d for %s thread #%d (%s):\n" 334 "# GetStackTrace(): %p\n" 335 "# GetFrameLocation(): %p\n", 336 j, kind, i, threadsDesc[i].threadName, 337 (void*)frameStack[j].method, (void*)qMethod); 338 nsk_jvmti_setFailStatus(); 339 } 340 if ( (suspended == NSK_TRUE) && (frameStack[j].location != qLocation) ) { 341 NSK_COMPLAIN6("Different location in stack frame #%d for %s thread #%d (%s):\n" 342 "# GetStackTrace(): %ld\n" 343 "# GetFrameLocation(): %ld\n", 344 j, kind, i, threadsDesc[i].threadName, 345 (long)frameStack[j].location, (long)qLocation); 346 nsk_jvmti_setFailStatus(); 347 } 348 349 /* find expected method */ 350 if (frameStack[j].method == threadsDesc[i].method) { 351 found++; 352 NSK_DISPLAY1(" found expected method: %s\n", 353 threadsDesc[i].methodName); 354 } 355 } 356 357 /* check if expected method frame found */ 358 if (found <= 0) { 359 NSK_COMPLAIN3("No expected method frame for %s thread #%d (%s)\n", 360 kind, i, threadsDesc[i].threadName); 361 nsk_jvmti_setFailStatus(); 362 } 363 } 364 365 /* test may continue */ 366 return NSK_TRUE; 367 } 368 369 /** 370 * Clean data: 371 * - dispose global references to tested threads 372 */ 373 static int clean() { 374 int i; 375 376 /* dispose global references to threads */ 377 for (i = 0; i < THREADS_COUNT; i++) { 378 NSK_TRACE(NSK_CPP_STUB2(DeleteGlobalRef, jni, threadsDesc[i].thread)); 379 NSK_TRACE(NSK_CPP_STUB2(DeleteGlobalRef, jni, threadsDesc[i].cls)); 380 } 381 382 return NSK_TRUE; 383 } 384 385 /* ============================================================================= */ 386 387 static volatile int testedThreadRunning = NSK_FALSE; 388 static volatile int testedThreadShouldFinish = NSK_FALSE; 389 390 /** Native running method in tested thread. */ 391 JNIEXPORT void JNICALL 392 Java_nsk_jvmti_scenarios_sampling_SP02_sp02t003ThreadRunningNative_testedMethod(JNIEnv* jni, 393 jobject obj) { 394 volatile int i = 0, n = 1000; 395 396 /* run in a loop */ 397 testedThreadRunning = NSK_TRUE; 398 while (!testedThreadShouldFinish) { 399 if (n <= 0) 400 n = 1000; 401 if (i >= n) 402 i = 0; 403 i++; 404 } 405 testedThreadRunning = NSK_FALSE; 406 } 407 408 /** Wait for native method is running. */ 409 JNIEXPORT jboolean JNICALL 410 Java_nsk_jvmti_scenarios_sampling_SP02_sp02t003ThreadRunningNative_checkReady(JNIEnv* jni, 411 jobject obj) { 412 while (!testedThreadRunning) { 413 nsk_jvmti_sleep(1000); 414 } 415 return testedThreadRunning ? JNI_TRUE : JNI_FALSE; 416 } 417 418 /** Let native method to finish. */ 419 JNIEXPORT void JNICALL 420 Java_nsk_jvmti_scenarios_sampling_SP02_sp02t003ThreadRunningNative_letFinish(JNIEnv* jni, 421 jobject obj) { 422 testedThreadShouldFinish = NSK_TRUE; 423 } 424 425 /* ============================================================================= */ 426 427 /** Agent library initialization. */ 428 #ifdef STATIC_BUILD 429 JNIEXPORT jint JNICALL Agent_OnLoad_sp02t003(JavaVM *jvm, char *options, void *reserved) { 430 return Agent_Initialize(jvm, options, reserved); 431 } 432 JNIEXPORT jint JNICALL Agent_OnAttach_sp02t003(JavaVM *jvm, char *options, void *reserved) { 433 return Agent_Initialize(jvm, options, reserved); 434 } 435 JNIEXPORT jint JNI_OnLoad_sp02t003(JavaVM *jvm, char *options, void *reserved) { 436 return JNI_VERSION_1_8; 437 } 438 #endif 439 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 440 441 /** Init framework and parse options. */ 442 if (!NSK_VERIFY(nsk_jvmti_parseOptions(options))) 443 return JNI_ERR; 444 445 timeout = nsk_jvmti_getWaitTime() * 60 * 1000; 446 447 /* create JVMTI environment */ 448 if (!NSK_VERIFY((jvmti = 449 nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL)) 450 return JNI_ERR; 451 452 /* add specific capabilities for suspending thread */ { 453 jvmtiCapabilities suspendCaps; 454 memset(&suspendCaps, 0, sizeof(suspendCaps)); 455 suspendCaps.can_suspend = 1; 456 if (!NSK_JVMTI_VERIFY( 457 NSK_CPP_STUB2(AddCapabilities, jvmti, &suspendCaps))) 458 return JNI_ERR; 459 } 460 461 /* register agent proc and arg */ 462 if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL))) 463 return JNI_ERR; 464 465 return JNI_OK; 466 } 467 468 /* ============================================================================= */ 469 470 }