1 /* 2 * Copyright (c) 2004, 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 <stdio.h> 25 #include <string.h> 26 #include "jvmti.h" 27 #include "agent_common.h" 28 #include "JVMTITools.h" 29 30 extern "C" { 31 32 33 #define PASSED 0 34 #define STATUS_FAILED 2 35 #define WAIT_START 100 36 37 static jvmtiEnv *jvmti = NULL; 38 static jvmtiCapabilities caps; 39 static jvmtiEventCallbacks callbacks; 40 static jrawMonitorID access_lock, wait_lock; 41 static jint result = PASSED; 42 static jboolean printdump = JNI_FALSE; 43 static jthread thr_ptr = NULL; 44 static jint wait_time = 0; 45 static jint state[] = { 46 JVMTI_THREAD_STATE_RUNNABLE, 47 JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER, 48 JVMTI_THREAD_STATE_IN_OBJECT_WAIT 49 }; 50 51 void printStateFlags(jint flags) { 52 if (flags & JVMTI_THREAD_STATE_SUSPENDED) 53 printf(" JVMTI_THREAD_STATE_SUSPENDED"); 54 if (flags & JVMTI_THREAD_STATE_INTERRUPTED) 55 printf(" JVMTI_THREAD_STATE_INTERRUPTED"); 56 if (flags & JVMTI_THREAD_STATE_IN_NATIVE) 57 printf(" JVMTI_THREAD_STATE_IN_NATIVE"); 58 printf(" (0x%0x)\n", flags); 59 } 60 61 void JNICALL VMInit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thr) { 62 jvmtiError err; 63 64 err = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, 65 JVMTI_EVENT_THREAD_START, NULL); 66 if (err != JVMTI_ERROR_NONE) { 67 printf("Failed to enable THREAD_START event: %s (%d)\n", 68 TranslateError(err), err); 69 result = STATUS_FAILED; 70 } 71 } 72 73 void JNICALL 74 ThreadStart(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread) { 75 jvmtiThreadInfo thrInfo; 76 jvmtiError err; 77 78 err = jvmti_env->RawMonitorEnter(access_lock); 79 if (err != JVMTI_ERROR_NONE) { 80 printf("(RawMonitorEnter) unexpected error: %s (%d)\n", 81 TranslateError(err), err); 82 result = STATUS_FAILED; 83 } 84 85 err = jvmti_env->GetThreadInfo(thread, &thrInfo); 86 if (err != JVMTI_ERROR_NONE) { 87 printf("(GetThreadInfo) unexpected error: %s (%d)\n", 88 TranslateError(err), err); 89 result = STATUS_FAILED; 90 } 91 if (thrInfo.name != NULL && strcmp(thrInfo.name, "thr1") == 0) { 92 thr_ptr = env->NewGlobalRef(thread); 93 if (printdump == JNI_TRUE) { 94 printf(">>> ThreadStart: \"%s\", 0x%p\n", thrInfo.name, thr_ptr); 95 } 96 } 97 98 err = jvmti_env->RawMonitorExit(access_lock); 99 if (err != JVMTI_ERROR_NONE) { 100 printf("(RawMonitorExit) unexpected error: %s (%d)\n", 101 TranslateError(err), err); 102 result = STATUS_FAILED; 103 } 104 } 105 106 #ifdef STATIC_BUILD 107 JNIEXPORT jint JNICALL Agent_OnLoad_thrstat002(JavaVM *jvm, char *options, void *reserved) { 108 return Agent_Initialize(jvm, options, reserved); 109 } 110 JNIEXPORT jint JNICALL Agent_OnAttach_thrstat002(JavaVM *jvm, char *options, void *reserved) { 111 return Agent_Initialize(jvm, options, reserved); 112 } 113 JNIEXPORT jint JNI_OnLoad_thrstat002(JavaVM *jvm, char *options, void *reserved) { 114 return JNI_VERSION_1_8; 115 } 116 #endif 117 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 118 jint res; 119 jvmtiError err; 120 121 if (options != NULL && strcmp(options, "printdump") == 0) { 122 printdump = JNI_TRUE; 123 } 124 125 res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1); 126 if (res != JNI_OK || jvmti == NULL) { 127 printf("Wrong result of a valid call to GetEnv !\n"); 128 return JNI_ERR; 129 } 130 131 err = jvmti->GetPotentialCapabilities(&caps); 132 if (err != JVMTI_ERROR_NONE) { 133 printf("(GetPotentialCapabilities) unexpected error: %s (%d)\n", 134 TranslateError(err), err); 135 return JNI_ERR; 136 } 137 138 err = jvmti->AddCapabilities(&caps); 139 if (err != JVMTI_ERROR_NONE) { 140 printf("(AddCapabilities) unexpected error: %s (%d)\n", 141 TranslateError(err), err); 142 return JNI_ERR; 143 } 144 145 err = jvmti->GetCapabilities(&caps); 146 if (err != JVMTI_ERROR_NONE) { 147 printf("(GetCapabilities) unexpected error: %s (%d)\n", 148 TranslateError(err), err); 149 return JNI_ERR; 150 } 151 152 if (!caps.can_suspend) { 153 printf("Warning: suspend/resume is not implemented\n"); 154 } 155 156 err = jvmti->CreateRawMonitor("_access_lock", &access_lock); 157 if (err != JVMTI_ERROR_NONE) { 158 printf("(CreateRawMonitor) unexpected error: %s (%d)\n", 159 TranslateError(err), err); 160 return JNI_ERR; 161 } 162 163 err = jvmti->CreateRawMonitor("_wait_lock", &wait_lock); 164 if (err != JVMTI_ERROR_NONE) { 165 printf("(CreateRawMonitor) unexpected error: %s (%d)\n", 166 TranslateError(err), err); 167 return JNI_ERR; 168 } 169 170 callbacks.VMInit = &VMInit; 171 callbacks.ThreadStart = &ThreadStart; 172 err = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)); 173 if (err != JVMTI_ERROR_NONE) { 174 printf("(SetEventCallbacks) unexpected error: %s (%d)\n", 175 TranslateError(err), err); 176 return JNI_ERR; 177 } 178 179 err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, 180 JVMTI_EVENT_VM_INIT, NULL); 181 if (err != JVMTI_ERROR_NONE) { 182 printf("Failed to enable VM_INIT event: %s (%d)\n", 183 TranslateError(err), err); 184 result = STATUS_FAILED; 185 } 186 187 return JNI_OK; 188 } 189 190 JNIEXPORT void JNICALL 191 Java_nsk_jvmti_GetThreadState_thrstat002_init(JNIEnv *env, jclass cls, 192 jint waitTime) { 193 wait_time = waitTime * 60000; 194 } 195 196 void wait_for(jint millis) { 197 jvmtiError err; 198 199 err = jvmti->RawMonitorEnter(wait_lock); 200 if (err != JVMTI_ERROR_NONE) { 201 printf("(RawMonitorEnter#check) unexpected error: %s (%d)\n", 202 TranslateError(err), err); 203 result = STATUS_FAILED; 204 } 205 err = jvmti->RawMonitorWait(wait_lock, (jlong)millis); 206 if (err != JVMTI_ERROR_NONE) { 207 printf("(RawMonitorWait#check) unexpected error: %s (%d)\n", 208 TranslateError(err), err); 209 result = STATUS_FAILED; 210 } 211 err = jvmti->RawMonitorExit(wait_lock); 212 if (err != JVMTI_ERROR_NONE) { 213 printf("(RawMonitorExit#check) unexpected error: %s (%d)\n", 214 TranslateError(err), err); 215 result = STATUS_FAILED; 216 } 217 } 218 219 JNIEXPORT void JNICALL 220 Java_nsk_jvmti_GetThreadState_thrstat002_checkStatus(JNIEnv *env, jclass cls, 221 jint statInd, jboolean suspended) { 222 jint thrState; 223 jint suspState = -1; 224 jint right_stat = (suspended ? JVMTI_THREAD_STATE_SUSPENDED : 0); 225 jvmtiError right_ans = (suspended ? JVMTI_ERROR_THREAD_SUSPENDED : JVMTI_ERROR_NONE); 226 const char *suspStr = (suspended ? ", suspended" : ""); 227 jvmtiError err; 228 jint millis; 229 jboolean timeout_is_reached; 230 unsigned int waited_millis; 231 232 if (jvmti == NULL) { 233 printf("JVMTI client was not properly loaded!\n"); 234 result = STATUS_FAILED; 235 return; 236 } 237 238 if (thr_ptr == NULL) { 239 printf("Missing thread \"thr1\" start event\n"); 240 result = STATUS_FAILED; 241 return; 242 } 243 244 if (!caps.can_suspend) { 245 return; 246 } 247 248 printf( "START checkStatus for \"thr1\" (0x%p%s), check state: %s\n", 249 thr_ptr, suspStr, TranslateState(state[statInd]) ); 250 251 timeout_is_reached = JNI_TRUE; 252 for (millis = WAIT_START, waited_millis=0; millis < wait_time; millis <<= 1) { 253 err = jvmti->GetThreadState(thr_ptr, &thrState); 254 if (err != JVMTI_ERROR_NONE) { 255 printf("(GetThreadState#%d) unexpected error: %s (%d)\n", 256 statInd, TranslateError(err), err); 257 result = STATUS_FAILED; 258 timeout_is_reached = JNI_FALSE; 259 break; 260 } 261 suspState = thrState & JVMTI_THREAD_STATE_SUSPENDED; 262 if (suspended || (thrState & JVMTI_THREAD_STATE_RUNNABLE) == 0 || 263 (state[statInd] == JVMTI_THREAD_STATE_RUNNABLE)) { 264 timeout_is_reached = JNI_FALSE; 265 break; 266 } 267 268 waited_millis += millis; 269 wait_for(millis); 270 } 271 272 if (printdump == JNI_TRUE) { 273 printf(">>> thread \"thr1\" (0x%p) state: %s (%d)\n", 274 thr_ptr, TranslateState(thrState), thrState); 275 printf(">>>\tflags:"); 276 printStateFlags(suspState); 277 } 278 279 if (timeout_is_reached == JNI_TRUE) { 280 printf("Error: timeout (%d secs) has been reached\n", waited_millis/1000); 281 } 282 if ((thrState & state[statInd]) == 0) { 283 printf("Wrong thread \"thr1\" (0x%p%s) state:\n", thr_ptr, suspStr); 284 printf(" expected: %s (%d)\n", 285 TranslateState(state[statInd]), state[statInd]); 286 printf(" actual: %s (%d)\n", 287 TranslateState(thrState), thrState); 288 result = STATUS_FAILED; 289 } 290 if (suspState != right_stat) { 291 printf("Wrong thread \"thr1\" (0x%p%s) state flags:\n", 292 thr_ptr, suspStr); 293 printf(" expected:"); 294 printStateFlags(right_stat); 295 printf(" actual:"); 296 printStateFlags(suspState); 297 result = STATUS_FAILED; 298 } 299 300 err = jvmti->SuspendThread(thr_ptr); 301 if (err != right_ans) { 302 printf("Wrong result of SuspendThread() for \"thr1\" (0x%p%s):\n", 303 thr_ptr, suspStr); 304 printf(" expected: %s (%d), actual: %s (%d)\n", 305 TranslateError(right_ans), right_ans, TranslateError(err), err); 306 result = STATUS_FAILED; 307 } 308 309 if (!suspended) { 310 // wait till thread is not suspended 311 timeout_is_reached = JNI_TRUE; 312 for (millis = WAIT_START, waited_millis=0; millis < wait_time; millis <<= 1) { 313 waited_millis += millis; 314 wait_for(millis); 315 err = jvmti->GetThreadState(thr_ptr, &thrState); 316 if (err != JVMTI_ERROR_NONE) { 317 printf("(GetThreadState#%d,after) unexpected error: %s (%d)\n", 318 statInd, TranslateError(err), err); 319 timeout_is_reached = JNI_FALSE; 320 result = STATUS_FAILED; 321 break; 322 } 323 suspState = thrState & JVMTI_THREAD_STATE_SUSPENDED; 324 if (suspState) { 325 timeout_is_reached = JNI_FALSE; 326 break; 327 } 328 } 329 330 if (timeout_is_reached == JNI_TRUE) { 331 printf("Error: timeout (%d secs) has been reached\n", waited_millis/1000); 332 } 333 if ((thrState & state[statInd]) == 0) { 334 printf("Wrong thread \"thr1\" (0x%p) state after SuspendThread:\n", 335 thr_ptr); 336 printf(" expected: %s (%d)\n", 337 TranslateState(state[statInd]), state[statInd]); 338 printf(" actual: %s (%d)\n", 339 TranslateState(thrState), thrState); 340 result = STATUS_FAILED; 341 } 342 if (suspState != JVMTI_THREAD_STATE_SUSPENDED) { 343 printf("Wrong thread \"thr1\" (0x%p) state flags", thr_ptr); 344 printf(" after SuspendThread:\n"); 345 printf(" expected:"); 346 printStateFlags(JVMTI_THREAD_STATE_SUSPENDED); 347 printf(" actual:"); 348 printStateFlags(suspState); 349 result = STATUS_FAILED; 350 } 351 err = jvmti->ResumeThread(thr_ptr); 352 if (err != JVMTI_ERROR_NONE) { 353 printf("(ResumeThread#%d) unexpected error: %s (%d)\n", 354 statInd, TranslateError(err), err); 355 result = STATUS_FAILED; 356 } 357 } 358 } 359 360 JNIEXPORT jint JNICALL 361 Java_nsk_jvmti_GetThreadState_thrstat002_getRes(JNIEnv *env, jclass cls) { 362 return result; 363 } 364 365 }