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