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 int minDepth; 48 jthread thread; 49 } ThreadDesc; 50 51 /* descriptions of tested threads */ 52 static ThreadDesc threadsDesc[THREADS_COUNT] = { 53 {"threadRunning", 2, NULL}, 54 {"threadEntering", 2, NULL}, 55 {"threadWaiting", 2, NULL}, 56 {"threadSleeping", 2, NULL}, 57 {"threadRunningInterrupted", 2, NULL}, 58 {"threadRunningNative", 2, NULL} 59 }; 60 61 /* ============================================================================= */ 62 63 /* testcase(s) */ 64 static int prepare(); 65 static int checkSuspendedThreads(); 66 static int suspendThreadsIndividually(int suspend); 67 static int clean(); 68 69 /* ============================================================================= */ 70 71 /** Agent algorithm. */ 72 static void JNICALL 73 agentProc(jvmtiEnv* jvmti, JNIEnv* agentJNI, void* arg) { 74 jni = agentJNI; 75 76 /* wait for initial sync */ 77 if (!nsk_jvmti_waitForSync(timeout)) 78 return; 79 80 /* perform testcase(s) */ 81 { 82 /* prepare data: find threads */ 83 NSK_DISPLAY0("Prepare data\n"); 84 if (!prepare()) { 85 nsk_jvmti_setFailStatus(); 86 return; 87 } 88 /* suspend threads */ 89 NSK_DISPLAY0("Suspend each thread\n"); 90 if (!suspendThreadsIndividually(NSK_TRUE)) 91 return; 92 93 /* check suspended threads */ 94 NSK_DISPLAY0("Check stack frames of suspended threads\n"); 95 if (!checkSuspendedThreads()) 96 return; 97 98 /* resume threads */ 99 NSK_DISPLAY0("Resume each thread\n"); 100 if (!suspendThreadsIndividually(NSK_FALSE)) 101 return; 102 103 /* clean date: delete threads references */ 104 NSK_DISPLAY0("Clean data\n"); 105 if (!clean()) { 106 nsk_jvmti_setFailStatus(); 107 return; 108 } 109 } 110 111 /* resume debugee after last sync */ 112 if (!nsk_jvmti_resumeSync()) 113 return; 114 } 115 116 /* ============================================================================= */ 117 118 /** 119 * Prepare data: 120 * - clean threads list 121 * - get all live threads with names 122 * - find tested threads by name 123 * - make global refs 124 */ 125 static int prepare() { 126 jthread *allThreadsList = NULL; 127 jint allThreadsCount = 0; 128 int found = 0; 129 int i; 130 131 NSK_DISPLAY1("Find tested threads: %d\n", THREADS_COUNT); 132 133 /* clean threads list */ 134 for (i = 0; i < THREADS_COUNT; i++) { 135 threadsDesc[i].thread = (jthread)NULL; 136 } 137 138 /* get all live threads */ 139 if (!NSK_JVMTI_VERIFY(jvmti->GetAllThreads(&allThreadsCount, &allThreadsList))) 140 return NSK_FALSE; 141 142 if (!NSK_VERIFY(allThreadsCount > 0 && allThreadsList != NULL)) 143 return NSK_FALSE; 144 145 /* find tested threads */ 146 for (i = 0; i < allThreadsCount; i++) { 147 jvmtiThreadInfo threadInfo; 148 149 if (!NSK_VERIFY(allThreadsList[i] != NULL)) 150 return NSK_FALSE; 151 152 /* get thread name (info) */ 153 if (!NSK_JVMTI_VERIFY(jvmti->GetThreadInfo(allThreadsList[i], &threadInfo))) 154 return NSK_FALSE; 155 156 /* find by name */ 157 if (threadInfo.name != NULL) { 158 int j; 159 160 for (j = 0; j < THREADS_COUNT; j++) { 161 if (strcmp(threadInfo.name, threadsDesc[j].threadName) == 0) { 162 threadsDesc[j].thread = allThreadsList[i]; 163 NSK_DISPLAY3(" thread #%d (%s): %p\n", 164 j, threadInfo.name, (void*)threadsDesc[j].thread); 165 } 166 } 167 } 168 } 169 170 /* deallocate all threads list */ 171 if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)allThreadsList))) 172 return NSK_FALSE; 173 174 /* check if all tested threads found */ 175 found = 0; 176 for (i = 0; i < THREADS_COUNT; i++) { 177 if (threadsDesc[i].thread == NULL) { 178 NSK_COMPLAIN2("Not found tested thread #%d (%s)\n", i, threadsDesc[i].threadName); 179 } else { 180 found++; 181 } 182 } 183 184 if (found < THREADS_COUNT) 185 return NSK_FALSE; 186 187 /* make global refs */ 188 for (i = 0; i < THREADS_COUNT; i++) { 189 if (!NSK_JNI_VERIFY(jni, (threadsDesc[i].thread = (jthread) 190 jni->NewGlobalRef(threadsDesc[i].thread)) != NULL)) 191 return NSK_FALSE; 192 } 193 194 return NSK_TRUE; 195 } 196 197 /** 198 * Suspend or resume tested threads. 199 */ 200 static int suspendThreadsIndividually(int suspend) { 201 int i; 202 203 for (i = 0; i < THREADS_COUNT; i++) { 204 if (suspend) { 205 NSK_DISPLAY2(" suspend thread #%d (%s)\n", i, threadsDesc[i].threadName); 206 if (!NSK_JVMTI_VERIFY(jvmti->SuspendThread(threadsDesc[i].thread))) 207 nsk_jvmti_setFailStatus(); 208 } else { 209 NSK_DISPLAY2(" resume thread #%d (%s)\n", i, threadsDesc[i].threadName); 210 if (!NSK_JVMTI_VERIFY(jvmti->ResumeThread(threadsDesc[i].thread))) 211 nsk_jvmti_setFailStatus(); 212 } 213 } 214 return NSK_TRUE; 215 } 216 217 /** 218 * Testcase: check tested threads 219 * - invoke getFrameCount() for each thread 220 * - check if frameCount is not less than minimal stack depth 221 * - invoke getStackTrace() for each thread 222 * - check if stack depth is equal to frameCount 223 * 224 * Returns NSK_TRUE if test may continue; or NSK_FALSE for test break. 225 */ 226 static int checkSuspendedThreads() { 227 int i; 228 229 /* check each thread */ 230 for (i = 0; i < THREADS_COUNT; i++) { 231 jint frameCount = 0; 232 jint frameStackSize = 0; 233 jvmtiFrameInfo frameStack[MAX_STACK_SIZE]; 234 int found = 0; 235 236 NSK_DISPLAY2(" thread #%d (%s):\n", i, threadsDesc[i].threadName); 237 238 /* get frame count */ 239 if (!NSK_JVMTI_VERIFY(jvmti->GetFrameCount(threadsDesc[i].thread, &frameCount))) { 240 nsk_jvmti_setFailStatus(); 241 return NSK_TRUE; 242 } 243 244 NSK_DISPLAY1(" frameCount: %d\n", (int)frameCount); 245 246 /* get stack trace */ 247 if (!NSK_JVMTI_VERIFY( 248 jvmti->GetStackTrace(threadsDesc[i].thread, 0, MAX_STACK_SIZE, frameStack, &frameStackSize))) { 249 nsk_jvmti_setFailStatus(); 250 return NSK_TRUE; 251 } 252 253 NSK_DISPLAY1(" stack depth: %d\n", (int)frameStackSize); 254 255 /* check frame count */ 256 if (frameCount < threadsDesc[i].minDepth) { 257 NSK_COMPLAIN4("Too few frameCount of suspended thread #%d (%s):\n" 258 "# got frameCount: %d\n" 259 "# expected minimum: %d\n", 260 i, threadsDesc[i].threadName, 261 (int)frameCount, threadsDesc[i].minDepth); 262 nsk_jvmti_setFailStatus(); 263 } 264 265 if (frameStackSize != frameCount) { 266 NSK_COMPLAIN4("Different frames count for suspended thread #%d (%s):\n" 267 "# getStackTrace(): %d\n" 268 "# getFrameCount(): %d\n", 269 i, threadsDesc[i].threadName, 270 (int)frameStackSize, (int)frameCount); 271 nsk_jvmti_setFailStatus(); 272 } 273 274 } 275 276 /* test may continue */ 277 return NSK_TRUE; 278 } 279 280 /** 281 * Clean data: 282 * - dispose global references to tested threads 283 */ 284 static int clean() { 285 int i; 286 287 /* dispose global references to threads */ 288 for (i = 0; i < THREADS_COUNT; i++) { 289 NSK_TRACE(jni->DeleteGlobalRef(threadsDesc[i].thread)); 290 } 291 292 return NSK_TRUE; 293 } 294 295 /* ============================================================================= */ 296 297 static volatile int testedThreadRunning = NSK_FALSE; 298 static volatile int testedThreadShouldFinish = NSK_FALSE; 299 300 /** Native running method in tested thread. */ 301 JNIEXPORT void JNICALL 302 Java_nsk_jvmti_scenarios_sampling_SP02_sp02t001ThreadRunningNative_testedMethod(JNIEnv* jni, 303 jobject obj) { 304 volatile int i = 0, n = 1000; 305 306 /* run in a loop */ 307 testedThreadRunning = NSK_TRUE; 308 while (!testedThreadShouldFinish) { 309 if (n <= 0) 310 n = 1000; 311 if (i >= n) 312 i = 0; 313 i++; 314 } 315 testedThreadRunning = NSK_FALSE; 316 } 317 318 /** Wait for native method is running. */ 319 JNIEXPORT jboolean JNICALL 320 Java_nsk_jvmti_scenarios_sampling_SP02_sp02t001ThreadRunningNative_checkReady(JNIEnv* jni, 321 jobject obj) { 322 while (!testedThreadRunning) { 323 nsk_jvmti_sleep(1000); 324 } 325 return testedThreadRunning ? JNI_TRUE : JNI_FALSE; 326 } 327 328 /** Let native method to finish. */ 329 JNIEXPORT void JNICALL 330 Java_nsk_jvmti_scenarios_sampling_SP02_sp02t001ThreadRunningNative_letFinish(JNIEnv* jni, 331 jobject obj) { 332 testedThreadShouldFinish = NSK_TRUE; 333 } 334 335 /* ============================================================================= */ 336 337 /** Agent library initialization. */ 338 #ifdef STATIC_BUILD 339 JNIEXPORT jint JNICALL Agent_OnLoad_sp02t001(JavaVM *jvm, char *options, void *reserved) { 340 return Agent_Initialize(jvm, options, reserved); 341 } 342 JNIEXPORT jint JNICALL Agent_OnAttach_sp02t001(JavaVM *jvm, char *options, void *reserved) { 343 return Agent_Initialize(jvm, options, reserved); 344 } 345 JNIEXPORT jint JNI_OnLoad_sp02t001(JavaVM *jvm, char *options, void *reserved) { 346 return JNI_VERSION_1_8; 347 } 348 #endif 349 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 350 351 /* init framework and parse options */ 352 if (!NSK_VERIFY(nsk_jvmti_parseOptions(options))) 353 return JNI_ERR; 354 355 timeout = nsk_jvmti_getWaitTime() * 60 * 1000; 356 357 /* create JVMTI environment */ 358 if (!NSK_VERIFY((jvmti = 359 nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL)) 360 return JNI_ERR; 361 362 /* add specific capabilities for suspending thread */ 363 { 364 jvmtiCapabilities suspendCaps; 365 memset(&suspendCaps, 0, sizeof(suspendCaps)); 366 suspendCaps.can_suspend = 1; 367 if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&suspendCaps))) 368 return JNI_ERR; 369 } 370 371 /* register agent proc and arg */ 372 if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL))) 373 return JNI_ERR; 374 375 return JNI_OK; 376 } 377 378 /* ============================================================================= */ 379 380 }