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