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(jvmti->Allocate(threadsCount * sizeof(jthread), 162 (unsigned char**)&threadsList[i]))) 163 return NSK_FALSE; 164 165 for (j = 0; j < threadsCount; j++) { 166 threadsList[i][j] = NULL; 167 } 168 } 169 170 /* get all live threads */ 171 if (!NSK_JVMTI_VERIFY(jvmti->GetAllThreads(&allThreadsCount, &allThreadsList))) 172 return NSK_FALSE; 173 174 if (!NSK_VERIFY(allThreadsCount > 0 && allThreadsList != NULL)) 175 return NSK_FALSE; 176 177 /* find tested threads */ 178 for (i = 0; i < allThreadsCount; i++) { 179 jvmtiThreadInfo threadInfo; 180 181 if (!NSK_VERIFY(allThreadsList[i] != NULL)) 182 return NSK_FALSE; 183 184 /* get thread name (info) */ 185 if (!NSK_JVMTI_VERIFY(jvmti->GetThreadInfo(allThreadsList[i], &threadInfo))) 186 return NSK_FALSE; 187 188 /* find by name */ 189 if (threadInfo.name != NULL) { 190 for (j = 0; j < THREADS_KINDS; j++) { 191 if (strcmp(threadInfo.name, threadsName[j]) == 0) { 192 int k = threadsCounts[j]; 193 if (k < threadsCount) 194 threadsList[j][k] = allThreadsList[i]; 195 threadsCounts[j]++; 196 } 197 } 198 } 199 } 200 201 /* deallocate all threads list */ 202 if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)allThreadsList))) 203 return NSK_FALSE; 204 205 /* check if all tested threads found */ 206 notfound = 0; 207 for (i = 0; i < THREADS_KINDS; i++) { 208 if (threadsCounts[i] != threadsCount) { 209 NSK_COMPLAIN3("Found unexpected number of tested threads (%s):\n" 210 "# found: %d\n" 211 "# expected: %d\n", 212 threadsName[i], threadsCounts[i], threadsCount); 213 nsk_jvmti_setFailStatus(); 214 notfound++; 215 } 216 } 217 218 if (notfound > 0) 219 return NSK_FALSE; 220 221 /* make global refs */ 222 for (i = 0; i < THREADS_KINDS; i++) { 223 for (j = 0; j < threadsCount; j++) { 224 if (!NSK_JNI_VERIFY(jni, (threadsList[i][j] = 225 jni->NewGlobalRef(threadsList[i][j])) != NULL)) 226 return NSK_FALSE; 227 } 228 } 229 230 return NSK_TRUE; 231 } 232 233 /** 234 * Suspend or resume tested threads list. 235 */ 236 static int suspendThreadsList(int suspend) { 237 jlong resultsSize = threadsCount * sizeof(jvmtiError); 238 jvmtiError* results = NULL; 239 const char* kind = (suspend ? "suspending" : "resuming"); 240 int i, j; 241 242 /* allocate results array */ 243 if (!NSK_JVMTI_VERIFY(jvmti->Allocate(resultsSize, (unsigned char**)&results))) { 244 nsk_jvmti_setFailStatus(); 245 return NSK_FALSE; 246 } 247 248 for (i = 0; i < THREADS_KINDS; i++) { 249 /* suspend or resume threads list */ 250 if (suspend) { 251 if (!NSK_JVMTI_VERIFY(jvmti->SuspendThreadList(threadsCount, threadsList[i], results))) 252 nsk_jvmti_setFailStatus(); 253 } else { 254 if (!NSK_JVMTI_VERIFY(jvmti->ResumeThreadList(threadsCount, threadsList[i], results))) 255 nsk_jvmti_setFailStatus(); 256 } 257 258 /* check results */ 259 for (j = 0; j < threadsCount; j++) { 260 if (results[j] != JVMTI_ERROR_NONE) { 261 NSK_COMPLAIN5("Unexpected result of %s thread #%d (%s):\n" 262 "# got result: %s (%d)\n", 263 kind, j, threadsName[i], 264 TranslateError(results[j]), (int)results[j]); 265 nsk_jvmti_setFailStatus(); 266 } 267 } 268 } 269 270 /* deallocate results array */ 271 if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)results))) { 272 nsk_jvmti_setFailStatus(); 273 } 274 275 return NSK_TRUE; 276 } 277 278 /** 279 * Suspend or resume tested threads individually. 280 */ 281 static int suspendThreadsIndividually(int suspend) { 282 int i, j; 283 284 for (i = 0; i < THREADS_KINDS; i++) { 285 for (j = 0; j < threadsCount; j++) { 286 if (suspend) { 287 NSK_DISPLAY2(" suspend thread #%d (%s)\n", j, threadsName[i]); 288 if (!NSK_JVMTI_VERIFY(jvmti->SuspendThread(threadsList[i][j]))) 289 nsk_jvmti_setFailStatus(); 290 } else { 291 NSK_DISPLAY2(" resume thread #%d (%s)\n", j, threadsName[i]); 292 if (!NSK_JVMTI_VERIFY(jvmti->ResumeThread(threadsList[i][j]))) 293 nsk_jvmti_setFailStatus(); 294 } 295 } 296 } 297 return NSK_TRUE; 298 } 299 300 /** 301 * Testcase: check tested threads 302 * - get thread state 303 * - wait for WAITIME if state is not expected 304 * - check if thread state is as expected 305 * 306 * Returns NSK_TRUE if test may continue; or NSK_FALSE for test break. 307 */ 308 static int checkThreads(int suspended, const char* kind, jlong timeout) { 309 int i, j; 310 311 /* check each thread */ 312 for (i = 0; i < THREADS_KINDS; i++) { 313 for (j = 0; j < threadsCount; j++) { 314 jint state = JVMTI_THREAD_STATE_NOT_STARTED; 315 jlong t = 0; 316 317 NSK_DISPLAY2(" thread #%d (%s):\n", j, threadsName[i]); 318 319 /* get thread state */ 320 if (!NSK_JVMTI_VERIFY(jvmti->GetThreadState(threadsList[i][j], &state))) { 321 nsk_jvmti_setFailStatus(); 322 return NSK_FALSE; 323 } 324 325 NSK_DISPLAY2(" flags = %s (%d)\n", 326 TranslateState(state), (int)state); 327 328 /* check SUSPENDED state */ 329 if (suspended) { 330 if (!(state & JVMTI_THREAD_STATE_SUSPENDED)) { 331 NSK_COMPLAIN5("No SUSPENDED state for %s thread #%d (%s):\n" 332 "# got flags: %s (%d)\n", 333 kind, j, threadsName[i], 334 TranslateState(state), (int)state); 335 nsk_jvmti_setFailStatus(); 336 } 337 } else { 338 if (state & JVMTI_THREAD_STATE_SUSPENDED) { 339 NSK_COMPLAIN5("Unexpected SUSPENDED state for %s thread #%d (%s):\n" 340 "# got flags: %s (%d)\n", 341 kind, j, threadsName[i], 342 TranslateState(state), (int)state); 343 nsk_jvmti_setFailStatus(); 344 } 345 } 346 } 347 } 348 349 /* test may continue */ 350 return NSK_TRUE; 351 } 352 353 /** 354 * Clean data: 355 * - dispose global references to tested threads 356 */ 357 static int clean() { 358 int i, j; 359 360 /* dispose global references to threads */ 361 for (i = 0; i < THREADS_KINDS; i++) { 362 for (j = 0; j < threadsCount; j++) { 363 NSK_TRACE(jni->DeleteGlobalRef(threadsList[i][j])); 364 } 365 } 366 367 /* deallocate memory */ 368 for (i = 0; i < THREADS_KINDS; i++) { 369 if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)threadsList[i]))) 370 return NSK_FALSE; 371 threadsList[i] = NULL; 372 } 373 374 return NSK_TRUE; 375 } 376 377 /* ============================================================================= */ 378 379 static volatile int testedThreadRunning = NSK_FALSE; 380 static volatile int testedThreadShouldFinish = NSK_FALSE; 381 382 /** Native running method in tested thread. */ 383 JNIEXPORT void JNICALL 384 Java_nsk_jvmti_scenarios_sampling_SP04_sp04t002ThreadRunningNative_nativeMethod(JNIEnv* jni, 385 jobject obj) { 386 volatile int i = 0, n = 1000; 387 388 /* run in a loop */ 389 testedThreadRunning = NSK_TRUE; 390 while (!testedThreadShouldFinish) { 391 if (n <= 0) 392 n = 1000; 393 if (i >= n) 394 i = 0; 395 i++; 396 } 397 testedThreadRunning = NSK_FALSE; 398 } 399 400 /** Wait for native method is running. */ 401 JNIEXPORT jboolean JNICALL 402 Java_nsk_jvmti_scenarios_sampling_SP04_sp04t002ThreadRunningNative_checkReady(JNIEnv* jni, 403 jobject obj) { 404 while (!testedThreadRunning) { 405 nsk_jvmti_sleep(1000); 406 } 407 return testedThreadRunning ? JNI_TRUE : JNI_FALSE; 408 } 409 410 /* Let native method to finish. */ 411 JNIEXPORT void JNICALL 412 Java_nsk_jvmti_scenarios_sampling_SP04_sp04t002ThreadRunningNative_letFinish(JNIEnv* jni, 413 jobject obj) { 414 testedThreadShouldFinish = NSK_TRUE; 415 } 416 417 /* ============================================================================= */ 418 419 /* Agent library initialization. */ 420 #ifdef STATIC_BUILD 421 JNIEXPORT jint JNICALL Agent_OnLoad_sp04t002(JavaVM *jvm, char *options, void *reserved) { 422 return Agent_Initialize(jvm, options, reserved); 423 } 424 JNIEXPORT jint JNICALL Agent_OnAttach_sp04t002(JavaVM *jvm, char *options, void *reserved) { 425 return Agent_Initialize(jvm, options, reserved); 426 } 427 JNIEXPORT jint JNI_OnLoad_sp04t002(JavaVM *jvm, char *options, void *reserved) { 428 return JNI_VERSION_1_8; 429 } 430 #endif 431 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 432 433 /* init framework and parse options */ 434 if (!NSK_VERIFY(nsk_jvmti_parseOptions(options))) 435 return JNI_ERR; 436 437 timeout = nsk_jvmti_getWaitTime() * 60 * 1000; 438 439 /* get number of threads for each kind */ 440 threadsCount = nsk_jvmti_findOptionIntValue("threads", DEFAULT_THREADS_NUMBER); 441 if (!NSK_VERIFY(threadsCount > 0)) 442 return JNI_ERR; 443 444 /* create JVMTI environment */ 445 if (!NSK_VERIFY((jvmti = 446 nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL)) 447 return JNI_ERR; 448 449 /* add specific capabilities for suspending thread */ 450 { 451 jvmtiCapabilities suspendCaps; 452 memset(&suspendCaps, 0, sizeof(suspendCaps)); 453 suspendCaps.can_suspend = 1; 454 if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&suspendCaps))) 455 return JNI_ERR; 456 } 457 458 /* register agent proc and arg */ 459 if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL))) 460 return JNI_ERR; 461 462 return JNI_OK; 463 } 464 465 /* ============================================================================= */ 466 467 }