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 threadsStatus[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 /* get JNI environment for agent thread */ 90 jni = nsk_jvmti_getAgentJNIEnv(); 91 92 /* wait for initial sync */ 93 if (!nsk_jvmti_waitForSync(timeout)) 94 return; 95 96 /* perform testcase(s) */ 97 { 98 /* prepare data: find threads */ 99 if (!prepare()) { 100 nsk_jvmti_setFailStatus(); 101 return; 102 } 103 104 /* testcase #1: check not suspended threads */ 105 NSK_DISPLAY0("Testcase #1: check state of not suspended threads\n"); 106 if (!checkThreads(NSK_FALSE, "not suspended", timeout)) 107 return; 108 109 /* suspend threads */ 110 NSK_DISPLAY0("Suspend threads list\n"); 111 if (!suspendThreadsList(NSK_TRUE)) 112 return; 113 114 /* testcase #2: check suspended threads */ 115 NSK_DISPLAY0("Testcase #2: check state of suspended threads\n"); 116 if (!checkThreads(NSK_TRUE, "suspended", 0)) 117 return; 118 119 /* resume threads */ 120 NSK_DISPLAY0("Resume threads individually\n"); 121 if (!suspendThreadsIndividually(NSK_FALSE)) 122 return; 123 124 /* testcase #3: check resumed threads */ 125 NSK_DISPLAY0("Testcase #3: check state of resumed threads\n"); 126 if (!checkThreads(NSK_FALSE, "resumed", 0)) 127 return; 128 129 /* clean date: delete threads references */ 130 if (!clean()) { 131 nsk_jvmti_setFailStatus(); 132 return; 133 } 134 } 135 136 /* resume debugee after last sync */ 137 if (!nsk_jvmti_resumeSync()) 138 return; 139 } 140 141 /* ============================================================================= */ 142 143 /** 144 * Prepare data: 145 * - clean threads list 146 * - get all live threads 147 * - get threads name 148 * - find tested threads 149 * - make global refs 150 */ 151 static int prepare() { 152 jthread *allThreadsList = NULL; 153 jint allThreadsCount = 0; 154 int notfound = 0; 155 int i, j; 156 157 NSK_DISPLAY1("Prepare: find tested threads: %d kinds\n", THREADS_KINDS); 158 159 /* allocate and clean threads list */ 160 for (i = 0; i < THREADS_KINDS; i++) { 161 threadsCounts[i] = 0; 162 threadsList[i] = NULL; 163 164 if (!NSK_JVMTI_VERIFY(jvmti->Allocate(threadsCount * sizeof(jthread), 165 (unsigned char**)&threadsList[i]))) 166 return NSK_FALSE; 167 168 for (j = 0; j < threadsCount; j++) { 169 threadsList[i][j] = NULL; 170 } 171 } 172 173 /* get all live threads */ 174 if (!NSK_JVMTI_VERIFY(jvmti->GetAllThreads(&allThreadsCount, &allThreadsList))) 175 return NSK_FALSE; 176 177 if (!NSK_VERIFY(allThreadsCount > 0 && allThreadsList != NULL)) 178 return NSK_FALSE; 179 180 /* find tested threads */ 181 for (i = 0; i < allThreadsCount; i++) { 182 jvmtiThreadInfo threadInfo; 183 184 if (!NSK_VERIFY(allThreadsList[i] != NULL)) 185 return NSK_FALSE; 186 187 /* get thread name (info) */ 188 if (!NSK_JVMTI_VERIFY(jvmti->GetThreadInfo(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(jvmti->Deallocate((unsigned char*)allThreadsList))) 206 return NSK_FALSE; 207 208 /* check if all tested threads found */ 209 notfound = 0; 210 for (i = 0; i < THREADS_KINDS; i++) { 211 if (threadsCounts[i] != threadsCount) { 212 NSK_COMPLAIN3("Found unexpected number of tested threads (%s):\n" 213 "# found: %d\n" 214 "# expected: %d\n", 215 threadsName[i], threadsCounts[i], threadsCount); 216 nsk_jvmti_setFailStatus(); 217 notfound++; 218 } 219 } 220 221 if (notfound > 0) 222 return NSK_FALSE; 223 224 /* make global refs */ 225 for (i = 0; i < THREADS_KINDS; i++) { 226 for (j = 0; j < threadsCount; j++) { 227 if (!NSK_JNI_VERIFY(jni, (threadsList[i][j] = 228 jni->NewGlobalRef(threadsList[i][j])) != NULL)) 229 return NSK_FALSE; 230 } 231 } 232 233 return NSK_TRUE; 234 } 235 236 /** 237 * Suspend or resume tested threads list. 238 */ 239 static int suspendThreadsList(int suspend) { 240 jlong resultsSize = threadsCount * sizeof(jvmtiError); 241 jvmtiError* results = NULL; 242 const char* kind = (suspend ? "suspending" : "resuming"); 243 int i, j; 244 245 /* allocate results array */ 246 if (!NSK_JVMTI_VERIFY(jvmti->Allocate(resultsSize, (unsigned char**)&results))) { 247 nsk_jvmti_setFailStatus(); 248 return NSK_FALSE; 249 } 250 251 for (i = 0; i < THREADS_KINDS; i++) { 252 /* suspend or resume threads list */ 253 if (suspend) { 254 if (!NSK_JVMTI_VERIFY(jvmti->SuspendThreadList(threadsCount, threadsList[i], results))) 255 nsk_jvmti_setFailStatus(); 256 } else { 257 if (!NSK_JVMTI_VERIFY(jvmti->ResumeThreadList(threadsCount, threadsList[i], results))) 258 nsk_jvmti_setFailStatus(); 259 } 260 261 /* check results */ 262 for (j = 0; j < threadsCount; j++) { 263 if (results[j] != JVMTI_ERROR_NONE) { 264 NSK_COMPLAIN5("Unexpected result of %s thread #%d (%s):\n" 265 "# got result: %s (%d)\n", 266 kind, j, threadsName[i], 267 TranslateError(results[j]), (int)results[j]); 268 nsk_jvmti_setFailStatus(); 269 } 270 } 271 } 272 273 /* deallocate results array */ 274 if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)results))) { 275 nsk_jvmti_setFailStatus(); 276 } 277 278 return NSK_TRUE; 279 } 280 281 /** 282 * Suspend or resume tested threads individually. 283 */ 284 static int suspendThreadsIndividually(int suspend) { 285 int i, j; 286 287 for (i = 0; i < THREADS_KINDS; i++) { 288 for (j = 0; j < threadsCount; j++) { 289 if (suspend) { 290 NSK_DISPLAY2(" suspend thread #%d (%s)\n", j, threadsName[i]); 291 if (!NSK_JVMTI_VERIFY(jvmti->SuspendThread(threadsList[i][j]))) 292 nsk_jvmti_setFailStatus(); 293 } else { 294 NSK_DISPLAY2(" resume thread #%d (%s)\n", j, threadsName[i]); 295 if (!NSK_JVMTI_VERIFY(jvmti->ResumeThread(threadsList[i][j]))) 296 nsk_jvmti_setFailStatus(); 297 } 298 } 299 } 300 return NSK_TRUE; 301 } 302 303 /** 304 * Testcase: check tested threads 305 * - get thread state and state 306 * - wait for WAITIME if state is not expected 307 * - check if thread state is as expected 308 * 309 * Returns NSK_TRUE if test may continue; or NSK_FALSE for test break. 310 */ 311 static int checkThreads(int suspended, const char* kind, jlong timeout) { 312 int i, j; 313 314 /* check each thread */ 315 for (i = 0; i < THREADS_KINDS; i++) { 316 for (j = 0; j < threadsCount; j++) { 317 jint state = JVMTI_THREAD_STATE_NOT_STARTED; 318 jlong t = 0; 319 320 NSK_DISPLAY2(" thread #%d (%s):\n", j, threadsName[i]); 321 322 /* get thread state */ 323 if (!NSK_JVMTI_VERIFY(jvmti->GetThreadState(threadsList[i][j], &state))) { 324 nsk_jvmti_setFailStatus(); 325 return NSK_FALSE; 326 } 327 328 NSK_DISPLAY2(" state = %s (%d)\n", 329 TranslateState(state), (int)state); 330 331 /* check SUSPENDED state */ 332 if (suspended) { 333 if (!(state & JVMTI_THREAD_STATE_SUSPENDED)) { 334 NSK_COMPLAIN5("No SUSPENDED state for %s thread #%d (%s):\n" 335 "# got flags: %s (%d)\n", 336 kind, j, threadsName[i], 337 TranslateState(state), (int)state); 338 nsk_jvmti_setFailStatus(); 339 } 340 } else { 341 if (state & JVMTI_THREAD_STATE_SUSPENDED) { 342 NSK_COMPLAIN5("Unexpected SUSPENDED state for %s thread #%d (%s):\n" 343 "# got flags: %s (%d)\n", 344 kind, j, threadsName[i], 345 TranslateState(state), (int)state); 346 nsk_jvmti_setFailStatus(); 347 } 348 } 349 } 350 } 351 352 /* test may continue */ 353 return NSK_TRUE; 354 } 355 356 /** 357 * Clean data: 358 * - dispose global references to tested threads 359 */ 360 static int clean() { 361 int i, j; 362 363 /* dispose global references to threads */ 364 for (i = 0; i < THREADS_KINDS; i++) { 365 for (j = 0; j < threadsCount; j++) { 366 NSK_TRACE(jni->DeleteGlobalRef(threadsList[i][j])); 367 } 368 } 369 370 /* deallocate memory */ 371 for (i = 0; i < THREADS_KINDS; i++) { 372 if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)threadsList[i]))) 373 return NSK_FALSE; 374 threadsList[i] = NULL; 375 } 376 377 return NSK_TRUE; 378 } 379 380 /* ============================================================================= */ 381 382 static volatile int testedThreadRunning = NSK_FALSE; 383 static volatile int testedThreadShouldFinish = NSK_FALSE; 384 385 /** Native running method in tested thread. */ 386 JNIEXPORT void JNICALL 387 Java_nsk_jvmti_scenarios_sampling_SP03_sp03t002ThreadRunningNative_nativeMethod(JNIEnv* jni, 388 jobject obj) { 389 volatile int i = 0, n = 1000; 390 391 /* run in a loop */ 392 testedThreadRunning = NSK_TRUE; 393 while (!testedThreadShouldFinish) { 394 if (n <= 0) 395 n = 1000; 396 if (i >= n) 397 i = 0; 398 i++; 399 } 400 testedThreadRunning = NSK_FALSE; 401 } 402 403 /** Wait for native method is running. */ 404 JNIEXPORT jboolean JNICALL 405 Java_nsk_jvmti_scenarios_sampling_SP03_sp03t002ThreadRunningNative_checkReady(JNIEnv* jni, 406 jobject obj) { 407 while (!testedThreadRunning) { 408 nsk_jvmti_sleep(1000); 409 } 410 return testedThreadRunning ? JNI_TRUE : JNI_FALSE; 411 } 412 413 /** Let native method to finish. */ 414 JNIEXPORT void JNICALL 415 Java_nsk_jvmti_scenarios_sampling_SP03_sp03t002ThreadRunningNative_letFinish(JNIEnv* jni, 416 jobject obj) { 417 testedThreadShouldFinish = NSK_TRUE; 418 } 419 420 /* ============================================================================= */ 421 422 /** Agent library initialization. */ 423 #ifdef STATIC_BUILD 424 JNIEXPORT jint JNICALL Agent_OnLoad_sp03t002(JavaVM *jvm, char *options, void *reserved) { 425 return Agent_Initialize(jvm, options, reserved); 426 } 427 JNIEXPORT jint JNICALL Agent_OnAttach_sp03t002(JavaVM *jvm, char *options, void *reserved) { 428 return Agent_Initialize(jvm, options, reserved); 429 } 430 JNIEXPORT jint JNI_OnLoad_sp03t002(JavaVM *jvm, char *options, void *reserved) { 431 return JNI_VERSION_1_8; 432 } 433 #endif 434 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 435 436 /* init framework and parse options */ 437 if (!NSK_VERIFY(nsk_jvmti_parseOptions(options))) 438 return JNI_ERR; 439 440 timeout = nsk_jvmti_getWaitTime() * 60 * 1000; 441 442 /* get number of threads for each kind */ 443 threadsCount = nsk_jvmti_findOptionIntValue("threads", DEFAULT_THREADS_NUMBER); 444 if (!NSK_VERIFY(threadsCount > 0)) 445 return JNI_ERR; 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 { 454 jvmtiCapabilities suspendCaps; 455 memset(&suspendCaps, 0, sizeof(suspendCaps)); 456 suspendCaps.can_suspend = 1; 457 if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&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 }