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(jvmti->GetAllThreads(&allThreadsCount, &allThreadsList))) 163 return NSK_FALSE; 164 165 if (!NSK_VERIFY(allThreadsCount > 0 && allThreadsList != NULL)) 166 return NSK_FALSE; 167 168 /* find tested threads */ 169 for (i = 0; i < allThreadsCount; i++) { 170 jvmtiThreadInfo threadInfo; 171 172 if (!NSK_VERIFY(allThreadsList[i] != NULL)) 173 return NSK_FALSE; 174 175 /* get thread name (info) */ 176 if (!NSK_JVMTI_VERIFY(jvmti->GetThreadInfo(allThreadsList[i], &threadInfo))) 177 return NSK_FALSE; 178 179 /* find by name */ 180 if (threadInfo.name != NULL) { 181 int j; 182 183 for (j = 0; j < THREADS_COUNT; j++) { 184 if (strcmp(threadInfo.name, threadsDesc[j].threadName) == 0) { 185 threadsDesc[j].thread = allThreadsList[i]; 186 NSK_DISPLAY3(" thread #%d (%s): %p\n", 187 j, threadInfo.name, (void*)threadsDesc[j].thread); 188 } 189 } 190 } 191 } 192 193 /* deallocate all threads list */ 194 if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)allThreadsList))) 195 return NSK_FALSE; 196 197 /* check if all tested threads found */ 198 found = 0; 199 for (i = 0; i < THREADS_COUNT; i++) { 200 if (threadsDesc[i].thread == NULL) { 201 NSK_COMPLAIN2("Not found tested thread #%d (%s)\n", i, threadsDesc[i].threadName); 202 } else { 203 found++; 204 } 205 } 206 207 if (found < THREADS_COUNT) 208 return NSK_FALSE; 209 210 /* get threads class and frame method */ 211 NSK_DISPLAY0("Find tested methods:\n"); 212 for (i = 0; i < THREADS_COUNT; i++) { 213 /* get thread class */ 214 if (!NSK_JNI_VERIFY(jni, (threadsDesc[i].cls = 215 jni->GetObjectClass(threadsDesc[i].thread)) != NULL)) 216 return NSK_FALSE; 217 /* get frame method */ 218 if (!NSK_JNI_VERIFY(jni, (threadsDesc[i].method = 219 jni->GetMethodID(threadsDesc[i].cls, threadsDesc[i].methodName, threadsDesc[i].methodSig)) != NULL)) 220 return NSK_FALSE; 221 222 NSK_DISPLAY4(" thread #%d (%s): %p (%s)\n", 223 i, threadsDesc[i].threadName, 224 (void*)threadsDesc[i].method, 225 threadsDesc[i].methodName); 226 } 227 228 /* make global refs */ 229 for (i = 0; i < THREADS_COUNT; i++) { 230 if (!NSK_JNI_VERIFY(jni, (threadsDesc[i].thread = (jthread) 231 jni->NewGlobalRef(threadsDesc[i].thread)) != NULL)) 232 return NSK_FALSE; 233 if (!NSK_JNI_VERIFY(jni, (threadsDesc[i].cls = (jclass) 234 jni->NewGlobalRef(threadsDesc[i].cls)) != NULL)) 235 return NSK_FALSE; 236 } 237 238 return NSK_TRUE; 239 } 240 241 /** 242 * Suspend or resume tested threads. 243 */ 244 static int suspendThreadsIndividually(int suspend) { 245 int i; 246 247 for (i = 0; i < THREADS_COUNT; i++) { 248 if (suspend) { 249 NSK_DISPLAY2(" suspend thread #%d (%s)\n", i, threadsDesc[i].threadName); 250 if (!NSK_JVMTI_VERIFY(jvmti->SuspendThread(threadsDesc[i].thread))) 251 nsk_jvmti_setFailStatus(); 252 } else { 253 NSK_DISPLAY2(" resume thread #%d (%s)\n", i, threadsDesc[i].threadName); 254 if (!NSK_JVMTI_VERIFY(jvmti->ResumeThread(threadsDesc[i].thread))) 255 nsk_jvmti_setFailStatus(); 256 } 257 } 258 return NSK_TRUE; 259 } 260 261 /** 262 * Testcase: check tested threads 263 * - call GetFrameCount() and then GetStackTrace() 264 * - for each stack frame of common depth GetFrameLocation() 265 * - compare frame ifno returned by GetFrameLocation() and GetStackTrace() 266 * - find expected frame for tested method 267 * 268 * Returns NSK_TRUE if test may continue; or NSK_FALSE for test break. 269 */ 270 static int checkThreads(int suspended, const char* kind) { 271 int i; 272 273 /* check each thread */ 274 for (i = 0; i < THREADS_COUNT; i++) { 275 jint frameCount = 0; 276 jint frameStackSize = 0; 277 jvmtiFrameInfo frameStack[MAX_STACK_SIZE]; 278 int commonDepth = 0; 279 int found = 0; 280 int j; 281 282 NSK_DISPLAY2(" thread #%d (%s):\n", i, threadsDesc[i].threadName); 283 284 /* get frame count */ 285 if (!NSK_JVMTI_VERIFY(jvmti->GetFrameCount(threadsDesc[i].thread, &frameCount))) { 286 nsk_jvmti_setFailStatus(); 287 return NSK_TRUE; 288 } 289 NSK_DISPLAY1(" frameCount: %d\n", (int)frameCount); 290 291 /* get stack trace */ 292 if (!NSK_JVMTI_VERIFY( 293 jvmti->GetStackTrace(threadsDesc[i].thread, 0, MAX_STACK_SIZE, frameStack, &frameStackSize))) { 294 nsk_jvmti_setFailStatus(); 295 return NSK_TRUE; 296 } 297 NSK_DISPLAY1(" stack depth: %d\n", (int)frameStackSize); 298 299 commonDepth = (frameCount < frameStackSize ? frameCount : frameStackSize); 300 NSK_DISPLAY1(" common: %d\n", (int)commonDepth); 301 302 /* check first commonDepth frames and find expected method there */ 303 found = 0; 304 for (j = 0; j < commonDepth; j++) { 305 jmethodID qMethod = (jmethodID)NULL; 306 jlocation qLocation = NSK_JVMTI_INVALID_JLOCATION; 307 308 NSK_DISPLAY3(" %d frame: method: %p, location: %ld\n", 309 j, (void*)frameStack[j].method, 310 (long)frameStack[j].location); 311 /* query frame location */ 312 if (!NSK_JVMTI_VERIFY( 313 jvmti->GetFrameLocation(threadsDesc[i].thread, j, &qMethod, &qLocation))) { 314 nsk_jvmti_setFailStatus(); 315 continue; 316 } 317 318 NSK_DISPLAY2(" queried: method: %p, location: %ld\n", 319 (void*)qMethod, (long)qLocation); 320 321 /* check frame equalaty */ 322 if (frameStack[j].method != qMethod) { 323 NSK_COMPLAIN6("Different method in stack frame #%d for %s thread #%d (%s):\n" 324 "# GetStackTrace(): %p\n" 325 "# GetFrameLocation(): %p\n", 326 j, kind, i, threadsDesc[i].threadName, 327 (void*)frameStack[j].method, (void*)qMethod); 328 nsk_jvmti_setFailStatus(); 329 } 330 if ( (suspended == NSK_TRUE) && (frameStack[j].location != qLocation) ) { 331 NSK_COMPLAIN6("Different location in stack frame #%d for %s thread #%d (%s):\n" 332 "# GetStackTrace(): %ld\n" 333 "# GetFrameLocation(): %ld\n", 334 j, kind, i, threadsDesc[i].threadName, 335 (long)frameStack[j].location, (long)qLocation); 336 nsk_jvmti_setFailStatus(); 337 } 338 339 /* find expected method */ 340 if (frameStack[j].method == threadsDesc[i].method) { 341 found++; 342 NSK_DISPLAY1(" found expected method: %s\n", 343 threadsDesc[i].methodName); 344 } 345 } 346 347 /* check if expected method frame found */ 348 if (found <= 0) { 349 NSK_COMPLAIN3("No expected method frame for %s thread #%d (%s)\n", 350 kind, i, threadsDesc[i].threadName); 351 nsk_jvmti_setFailStatus(); 352 } 353 } 354 355 /* test may continue */ 356 return NSK_TRUE; 357 } 358 359 /** 360 * Clean data: 361 * - dispose global references to tested threads 362 */ 363 static int clean() { 364 int i; 365 366 /* dispose global references to threads */ 367 for (i = 0; i < THREADS_COUNT; i++) { 368 NSK_TRACE(jni->DeleteGlobalRef(threadsDesc[i].thread)); 369 NSK_TRACE(jni->DeleteGlobalRef(threadsDesc[i].cls)); 370 } 371 372 return NSK_TRUE; 373 } 374 375 /* ============================================================================= */ 376 377 static volatile int testedThreadRunning = NSK_FALSE; 378 static volatile int testedThreadShouldFinish = NSK_FALSE; 379 380 /** Native running method in tested thread. */ 381 JNIEXPORT void JNICALL 382 Java_nsk_jvmti_scenarios_sampling_SP02_sp02t003ThreadRunningNative_testedMethod(JNIEnv* jni, 383 jobject obj) { 384 volatile int i = 0, n = 1000; 385 386 /* run in a loop */ 387 testedThreadRunning = NSK_TRUE; 388 while (!testedThreadShouldFinish) { 389 if (n <= 0) 390 n = 1000; 391 if (i >= n) 392 i = 0; 393 i++; 394 } 395 testedThreadRunning = NSK_FALSE; 396 } 397 398 /** Wait for native method is running. */ 399 JNIEXPORT jboolean JNICALL 400 Java_nsk_jvmti_scenarios_sampling_SP02_sp02t003ThreadRunningNative_checkReady(JNIEnv* jni, 401 jobject obj) { 402 while (!testedThreadRunning) { 403 nsk_jvmti_sleep(1000); 404 } 405 return testedThreadRunning ? JNI_TRUE : JNI_FALSE; 406 } 407 408 /** Let native method to finish. */ 409 JNIEXPORT void JNICALL 410 Java_nsk_jvmti_scenarios_sampling_SP02_sp02t003ThreadRunningNative_letFinish(JNIEnv* jni, 411 jobject obj) { 412 testedThreadShouldFinish = NSK_TRUE; 413 } 414 415 /* ============================================================================= */ 416 417 /** Agent library initialization. */ 418 #ifdef STATIC_BUILD 419 JNIEXPORT jint JNICALL Agent_OnLoad_sp02t003(JavaVM *jvm, char *options, void *reserved) { 420 return Agent_Initialize(jvm, options, reserved); 421 } 422 JNIEXPORT jint JNICALL Agent_OnAttach_sp02t003(JavaVM *jvm, char *options, void *reserved) { 423 return Agent_Initialize(jvm, options, reserved); 424 } 425 JNIEXPORT jint JNI_OnLoad_sp02t003(JavaVM *jvm, char *options, void *reserved) { 426 return JNI_VERSION_1_8; 427 } 428 #endif 429 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 430 431 /** Init framework and parse options. */ 432 if (!NSK_VERIFY(nsk_jvmti_parseOptions(options))) 433 return JNI_ERR; 434 435 timeout = nsk_jvmti_getWaitTime() * 60 * 1000; 436 437 /* create JVMTI environment */ 438 if (!NSK_VERIFY((jvmti = 439 nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL)) 440 return JNI_ERR; 441 442 /* add specific capabilities for suspending thread */ { 443 jvmtiCapabilities suspendCaps; 444 memset(&suspendCaps, 0, sizeof(suspendCaps)); 445 suspendCaps.can_suspend = 1; 446 if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&suspendCaps))) 447 return JNI_ERR; 448 } 449 450 /* register agent proc and arg */ 451 if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL))) 452 return JNI_ERR; 453 454 return JNI_OK; 455 } 456 457 /* ============================================================================= */ 458 459 }