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 <assert.h> 25 #include <jni.h> 26 #include <jvmti.h> 27 #include <stdio.h> 28 #include "jni_tools.h" 29 30 #ifdef __cplusplus 31 extern "C" { 32 #endif 33 34 #define FIND_CLASS(_class, _className)\ 35 if (!NSK_JNI_VERIFY(env, (_class = \ 36 NSK_CPP_STUB2(FindClass, env, _className)) != NULL))\ 37 return 38 39 #define GET_OBJECT_CLASS(_class, _obj)\ 40 if (!NSK_JNI_VERIFY(env, (_class = \ 41 NSK_CPP_STUB2(GetObjectClass, env, _obj)) != NULL))\ 42 return 43 44 #define GET_STATIC_FIELD_ID(_fieldID, _class, _fieldName, _fieldSig)\ 45 if (!NSK_JNI_VERIFY(env, (_fieldID = \ 46 NSK_CPP_STUB4(GetStaticFieldID, env, _class,\ 47 _fieldName, _fieldSig)) != NULL))\ 48 return 49 50 #define GET_STATIC_OBJ_FIELD(_value, _class, _fieldName, _fieldSig)\ 51 GET_STATIC_FIELD_ID(field, _class, _fieldName, _fieldSig);\ 52 _value = NSK_CPP_STUB3(GetStaticObjectField, env, _class, \ 53 field) 54 55 #define GET_STATIC_BOOL_FIELD(_value, _class, _fieldName)\ 56 GET_STATIC_FIELD_ID(field, _class, _fieldName, "Z");\ 57 _value = NSK_CPP_STUB3(GetStaticBooleanField, env, _class, field) 58 59 #define GET_FIELD_ID(_fieldID, _class, _fieldName, _fieldSig)\ 60 if (!NSK_JNI_VERIFY(env, (_fieldID = \ 61 NSK_CPP_STUB4(GetFieldID, env, _class,\ 62 _fieldName, _fieldSig)) != NULL))\ 63 return 64 65 #define GET_INT_FIELD(_value, _obj, _class, _fieldName)\ 66 GET_FIELD_ID(field, _class, _fieldName, "I");\ 67 _value = NSK_CPP_STUB3(GetIntField, env, _obj, field) 68 69 #define GET_BOOL_FIELD(_value, _obj, _class, _fieldName)\ 70 GET_FIELD_ID(field, _class, _fieldName, "Z");\ 71 _value = NSK_CPP_STUB3(GetBooleanField, env, _obj, field) 72 73 #define GET_LONG_FIELD(_value, _obj, _class, _fieldName)\ 74 GET_FIELD_ID(field, _class, _fieldName, "J");\ 75 _value = NSK_CPP_STUB3(GetLongField, env, _obj, field) 76 77 #define GET_STATIC_INT_FIELD(_value, _class, _fieldName)\ 78 GET_STATIC_FIELD_ID(field, _class, _fieldName, "I");\ 79 _value = NSK_CPP_STUB3(GetStaticIntField, env, _class, field) 80 81 #define SET_INT_FIELD(_obj, _class, _fieldName, _newValue)\ 82 GET_FIELD_ID(field, _class, _fieldName, "I");\ 83 NSK_CPP_STUB4(SetIntField, env, _obj, field, _newValue) 84 85 #define GET_OBJ_FIELD(_value, _obj, _class, _fieldName, _fieldSig)\ 86 GET_FIELD_ID(field, _class, _fieldName, _fieldSig);\ 87 _value = NSK_CPP_STUB3(GetObjectField, env, _obj, field) 88 89 90 #define GET_ARR_ELEMENT(_arr, _index)\ 91 NSK_CPP_STUB3(GetObjectArrayElement, env, _arr, _index) 92 93 #define SET_ARR_ELEMENT(_arr, _index, _newValue)\ 94 NSK_CPP_STUB4(SetObjectArrayElement, env, _arr, _index, _newValue) 95 96 #define GET_STATIC_METHOD_ID(_methodID, _class, _methodName, _sig)\ 97 if (!NSK_JNI_VERIFY(env, (_methodID = \ 98 NSK_CPP_STUB4(GetStaticMethodID, env, _class,\ 99 _methodName, _sig)) != NULL))\ 100 return 101 102 #define GET_METHOD_ID(_methodID, _class, _methodName, _sig)\ 103 if (!NSK_JNI_VERIFY(env, (_methodID = \ 104 NSK_CPP_STUB4(GetMethodID, env, _class,\ 105 _methodName, _sig)) != NULL))\ 106 return 107 108 #define CALL_STATIC_VOID_NOPARAM(_class, _methodName)\ 109 GET_STATIC_METHOD_ID(method, _class, _methodName, "()V");\ 110 if (!NSK_JNI_VERIFY_VOID(env, NSK_CPP_STUB3(CallStaticVoidMethod, env,\ 111 _class, method)))\ 112 return 113 114 #define CALL_STATIC_VOID(_class, _methodName, _sig, _param)\ 115 GET_STATIC_METHOD_ID(method, _class, _methodName, _sig);\ 116 if (!NSK_JNI_VERIFY_VOID(env, NSK_CPP_STUB4(CallStaticVoidMethod, env,\ 117 _class, method, _param)))\ 118 return 119 120 #define CALL_STATIC_OBJ(_value, _class, _methodName, _sig, _param)\ 121 GET_STATIC_METHOD_ID(method, _class, _methodName, _sig);\ 122 _value = NSK_CPP_STUB4(CallStaticObjectMethod, env, _class, method, _param) 123 124 #define CALL_VOID_NOPARAM(_obj, _class, _methodName)\ 125 GET_METHOD_ID(method, _class, _methodName, "()V");\ 126 if (!NSK_JNI_VERIFY_VOID(env, NSK_CPP_STUB3(CallVoidMethod, env, _obj,\ 127 method)))\ 128 return 129 130 #define CALL_VOID(_obj, _class, _methodName, _sig, _param)\ 131 GET_METHOD_ID(method, _class, _methodName, "()V");\ 132 if (!NSK_JNI_VERIFY_VOID(env, NSK_CPP_STUB4(CallVoidMethod, env, _obj,\ 133 method, _param)))\ 134 return 135 136 #define CALL_VOID2(_obj, _class, _methodName, _sig, _param1, _param2)\ 137 GET_METHOD_ID(method, _class, _methodName, _sig);\ 138 if (!NSK_JNI_VERIFY_VOID(env, NSK_CPP_STUB5(CallVoidMethod, env, _obj, \ 139 method, _param1, _param2)))\ 140 return 141 142 #define CALL_INT_NOPARAM(_value, _obj, _class, _methodName)\ 143 GET_METHOD_ID(method, _class, _methodName, "()I");\ 144 _value = NSK_CPP_STUB3(CallIntMethod, env, _obj, method) 145 146 #define NEW_OBJ(_obj, _class, _constructorName, _sig, _params)\ 147 GET_METHOD_ID(method, _class, _constructorName, _sig);\ 148 if (!NSK_JNI_VERIFY(env, (_obj = \ 149 NSK_CPP_STUB4(NewObject, env, _class, method, _params)) != NULL))\ 150 return 151 152 #define MONITOR_ENTER(x) \ 153 NSK_JNI_VERIFY(env, NSK_CPP_STUB2(MonitorEnter, env, x) == 0) 154 155 #define MONITOR_EXIT(x) \ 156 NSK_JNI_VERIFY(env, NSK_CPP_STUB2(MonitorExit, env, x) == 0) 157 158 #define TRACE(msg)\ 159 GET_OBJ_FIELD(logger, obj, threadClass, "logger", "Lnsk/share/Log$Logger;");\ 160 jmsg = NSK_CPP_STUB2(NewStringUTF, env, msg);\ 161 CALL_VOID2(logger, loggerClass, "trace",\ 162 "(ILjava/lang/String;)V", 50, jmsg) 163 164 static const char *SctrlClassName="nsk/monitoring/share/ThreadController"; 165 static const char *SthreadControllerSig 166 = "Lnsk/monitoring/share/ThreadController;"; 167 168 static const char *SThreadsGroupLocksSig 169 ="Lnsk/monitoring/share/ThreadsGroupLocks;"; 170 static const char *SThreadsGroupLocksClassName 171 ="nsk/monitoring/share/ThreadsGroupLocks"; 172 173 174 static const char *SbringState_mn="bringState"; 175 static const char *SnativeBringState_mn="nativeBringState"; 176 static const char *SrecursiveMethod_mn="recursiveMethod"; 177 static const char *SnativeRecursiveMethod_mn="nativeRecursiveMethod"; 178 static const char *SloggerClassName = "nsk/share/Log$Logger"; 179 180 static const char *Snoparams="()V"; 181 static const char *Slongparam="(J)V"; 182 183 /* 184 * Class: nsk_monitoring_share_BaseThread 185 * Method: nativeRecursiveMethod 186 * Signature: ()V 187 */ 188 JNIEXPORT void JNICALL Java_nsk_monitoring_share_BaseThread_nativeRecursiveMethod(JNIEnv * env,jobject obj)189 Java_nsk_monitoring_share_BaseThread_nativeRecursiveMethod(JNIEnv *env, 190 jobject obj) { 191 jint currDepth, maxDepth; 192 jobject logger; 193 jstring jmsg; 194 jfieldID field; 195 jmethodID method; 196 197 jobject controller; 198 jclass threadClass, ctrlClass, loggerClass; 199 200 int invocationType; 201 202 GET_OBJECT_CLASS(threadClass, obj); 203 FIND_CLASS(ctrlClass, SctrlClassName); 204 FIND_CLASS(loggerClass, SloggerClassName); 205 206 207 /* currDepth++ */ 208 GET_INT_FIELD(currDepth, obj, threadClass, "currentDepth"); 209 currDepth++; 210 SET_INT_FIELD(obj, threadClass, "currentDepth", currDepth); 211 212 GET_OBJ_FIELD(controller, obj, threadClass, "controller", 213 SthreadControllerSig); 214 GET_INT_FIELD(maxDepth, controller, ctrlClass, "maxDepth"); 215 216 GET_STATIC_INT_FIELD(invocationType, ctrlClass, "invocationType"); 217 218 if (maxDepth - currDepth > 0) 219 { 220 CALL_STATIC_VOID_NOPARAM(threadClass, "yield"); 221 222 if (invocationType == 2/*MIXED_TYPE*/) 223 { 224 CALL_VOID_NOPARAM(obj, threadClass, SrecursiveMethod_mn); 225 } 226 else 227 { 228 CALL_VOID_NOPARAM(obj, threadClass, SnativeRecursiveMethod_mn); 229 } 230 } 231 else 232 { 233 TRACE("state has been reached"); 234 if (invocationType == 2/*MIXED_TYPE*/) 235 { 236 CALL_VOID_NOPARAM(obj, threadClass, SbringState_mn); 237 } 238 else 239 { 240 CALL_VOID_NOPARAM(obj, threadClass, SnativeBringState_mn); 241 } 242 } 243 244 currDepth--; 245 GET_OBJECT_CLASS(threadClass, obj); 246 SET_INT_FIELD(obj, threadClass, "currentDepth", currDepth); 247 } 248 249 /* 250 * Class: nsk_monitoring_share_BlockedThread 251 * Method: nativeBringState 252 * Signature: ()V 253 */ 254 JNIEXPORT void JNICALL Java_nsk_monitoring_share_BlockedThread_nativeBringState(JNIEnv * env,jobject obj)255 Java_nsk_monitoring_share_BlockedThread_nativeBringState(JNIEnv *env, 256 jobject obj) { 257 jobject logger; 258 jstring jmsg; 259 jfieldID field; 260 jmethodID method; 261 262 jclass threadClass, loggerClass; 263 264 jobject STATE; 265 266 //ThreadsGroupLocks: 267 jclass ThreadsGroupLocks; 268 jobject threadsGroupLocks; 269 jmethodID getBarrier; 270 271 272 //CountDownLatch 273 jobject barrier; 274 jclass CountDownLatch; 275 276 //Blocker 277 jobject blocker; 278 jclass Blocker; 279 280 GET_OBJECT_CLASS(threadClass, obj); 281 282 FIND_CLASS(loggerClass, SloggerClassName); 283 FIND_CLASS(ThreadsGroupLocks, SThreadsGroupLocksClassName); 284 FIND_CLASS(Blocker, "Lnsk/monitoring/share/ThreadsGroupLocks$Blocker;"); 285 FIND_CLASS(CountDownLatch, "nsk/monitoring/share/ThreadsGroupLocks$PlainCountDownLatch"); 286 287 GET_OBJ_FIELD(threadsGroupLocks, obj, threadClass, "threadsGroupLocks", SThreadsGroupLocksSig); 288 GET_STATIC_OBJ_FIELD(STATE, threadClass, "STATE", "Ljava/lang/Thread$State;"); 289 GET_OBJ_FIELD(blocker, threadsGroupLocks, ThreadsGroupLocks, "blocker", "Lnsk/monitoring/share/ThreadsGroupLocks$Blocker;"); 290 291 getBarrier = (*env)->GetMethodID(env, ThreadsGroupLocks, "getBarrier", 292 "(Ljava/lang/Thread$State;)Lnsk/monitoring/share/ThreadsGroupLocks$PlainCountDownLatch;"); 293 barrier = (*env)->CallObjectMethod(env, threadsGroupLocks, getBarrier, STATE); 294 295 296 TRACE("entering to monitor"); 297 298 CALL_VOID_NOPARAM(barrier, CountDownLatch, "countDown"); 299 CALL_VOID_NOPARAM(blocker, Blocker, "block"); 300 TRACE("exiting from monitor"); 301 302 } 303 304 /* 305 * Class: nsk_monitoring_share_WaitingThread 306 * Method: nativeBringState 307 * Signature: ()V 308 */ 309 JNIEXPORT void JNICALL Java_nsk_monitoring_share_WaitingThread_nativeBringState(JNIEnv * env,jobject obj)310 Java_nsk_monitoring_share_WaitingThread_nativeBringState(JNIEnv *env, 311 jobject obj) { 312 jobject logger; 313 jstring jmsg; 314 jfieldID field; 315 jmethodID method; 316 317 jclass threadClass, loggerClass; 318 319 //STATE 320 jobject STATE; 321 322 //ThreadsGroupLocks: 323 jclass ThreadsGroupLocks; 324 jobject threadsGroupLocks; 325 jmethodID getBarrier; 326 327 //CountDownLatch 328 jobject barrier; 329 jclass CountDownLatch; 330 331 GET_OBJECT_CLASS(threadClass, obj); 332 333 FIND_CLASS(loggerClass, SloggerClassName); 334 FIND_CLASS(ThreadsGroupLocks, "nsk/monitoring/share/ThreadsGroupLocks"); 335 FIND_CLASS(CountDownLatch, "nsk/monitoring/share/ThreadsGroupLocks$PlainCountDownLatch"); 336 337 GET_STATIC_OBJ_FIELD(STATE, threadClass, "STATE", "Ljava/lang/Thread$State;"); 338 GET_OBJ_FIELD(threadsGroupLocks, obj, threadClass, "threadsGroupLocks", "Lnsk/monitoring/share/ThreadsGroupLocks;"); 339 340 getBarrier = (*env)->GetMethodID(env, ThreadsGroupLocks, "getBarrier", 341 "(Ljava/lang/Thread$State;)Lnsk/monitoring/share/ThreadsGroupLocks$PlainCountDownLatch;"); 342 barrier = (*env)->CallObjectMethod(env, threadsGroupLocks, getBarrier, STATE); 343 CALL_VOID_NOPARAM(barrier, CountDownLatch, "countDown"); 344 345 TRACE("waiting on a monitor"); 346 CALL_VOID_NOPARAM(barrier, CountDownLatch, "await"); 347 } 348 349 /* 350 * Class: nsk_monitoring_share_SleepingThread 351 * Method: nativeBringState 352 * Signature: ()V 353 */ 354 JNIEXPORT void JNICALL Java_nsk_monitoring_share_SleepingThread_nativeBringState(JNIEnv * env,jobject obj)355 Java_nsk_monitoring_share_SleepingThread_nativeBringState(JNIEnv *env, 356 jobject obj) { 357 jfieldID field; 358 jmethodID method; 359 360 jclass threadClass, loggerClass; 361 362 //STATE 363 jobject STATE; 364 365 //ThreadsGroupLocks: 366 jclass ThreadsGroupLocks; 367 jobject threadsGroupLocks; 368 jmethodID getBarrier; 369 370 //CountDownLatch 371 jobject barrier; 372 jclass CountDownLatch; 373 374 //Thread 375 jclass Thread; 376 377 jlong sleepTime = 20 * 60 * 1000; 378 379 380 GET_OBJECT_CLASS(threadClass, obj); 381 382 FIND_CLASS(loggerClass, SloggerClassName); 383 FIND_CLASS(ThreadsGroupLocks, "nsk/monitoring/share/ThreadsGroupLocks"); 384 FIND_CLASS(CountDownLatch, "nsk/monitoring/share/ThreadsGroupLocks$PlainCountDownLatch"); 385 386 GET_STATIC_OBJ_FIELD(STATE, threadClass, "STATE", "Ljava/lang/Thread$State;"); 387 GET_OBJ_FIELD(threadsGroupLocks, obj, threadClass, "threadsGroupLocks", "Lnsk/monitoring/share/ThreadsGroupLocks;"); 388 389 // Thread.sleep(3600 * 1000); 390 FIND_CLASS(Thread, "java/lang/Thread"); 391 392 getBarrier = (*env)->GetMethodID(env, ThreadsGroupLocks, "getBarrier", 393 "(Ljava/lang/Thread$State;)Lnsk/monitoring/share/ThreadsGroupLocks$PlainCountDownLatch;"); 394 barrier = (*env)->CallObjectMethod(env, threadsGroupLocks, getBarrier, STATE); 395 CALL_VOID_NOPARAM(barrier, CountDownLatch, "countDown"); 396 397 CALL_STATIC_VOID(Thread, "sleep", "(J)V", sleepTime); 398 } 399 400 /* 401 * Class: nsk_monitoring_share_RunningThread 402 * Method: nativeBringState 403 * Signature: ()V 404 */ 405 JNIEXPORT void JNICALL Java_nsk_monitoring_share_RunningThread_nativeBringState(JNIEnv * env,jobject obj)406 Java_nsk_monitoring_share_RunningThread_nativeBringState(JNIEnv *env, 407 jobject obj) { 408 jobject logger; 409 jstring jmsg; 410 jfieldID field; 411 jmethodID method; 412 413 jclass threadClass, loggerClass; 414 415 //STATE 416 jobject STATE; 417 418 //ThreadsGroupLocks: 419 jclass ThreadsGroupLocks; 420 jobject threadsGroupLocks; 421 jmethodID getBarrier; 422 423 //CountDownLatch 424 jobject barrier; 425 jclass CountDownLatch; 426 427 //Thread 428 jclass Thread; 429 430 //runnableCanExit 431 jboolean flag = JNI_FALSE; 432 433 GET_OBJECT_CLASS(threadClass, obj); 434 435 FIND_CLASS(loggerClass, SloggerClassName); 436 FIND_CLASS(ThreadsGroupLocks, "nsk/monitoring/share/ThreadsGroupLocks"); 437 FIND_CLASS(CountDownLatch, "nsk/monitoring/share/ThreadsGroupLocks$PlainCountDownLatch"); 438 439 GET_STATIC_OBJ_FIELD(STATE, threadClass, "STATE", "Ljava/lang/Thread$State;"); 440 GET_OBJ_FIELD(threadsGroupLocks, obj, threadClass, "threadsGroupLocks", "Lnsk/monitoring/share/ThreadsGroupLocks;"); 441 442 // Thread.sleep(3600 * 1000); 443 FIND_CLASS(Thread, "java/lang/Thread"); 444 445 getBarrier = (*env)->GetMethodID(env, ThreadsGroupLocks, "getBarrier", 446 "(Ljava/lang/Thread$State;)Lnsk/monitoring/share/ThreadsGroupLocks$PlainCountDownLatch;"); 447 448 TRACE("running loop"); 449 450 barrier = (*env)->CallObjectMethod(env, threadsGroupLocks, getBarrier, STATE); 451 CALL_VOID_NOPARAM(barrier, CountDownLatch, "countDown"); 452 453 // while (!threadsGroupLocks.runnableCanExit.get()) { 454 // Thread.yield(); 455 // } 456 while(flag==JNI_FALSE) 457 { 458 GET_BOOL_FIELD(flag, threadsGroupLocks, ThreadsGroupLocks, "runnableCanExit"); 459 CALL_STATIC_VOID_NOPARAM(Thread, "yield"); 460 } 461 462 } 463 getStateName(JNIEnv * env,jint state)464 jstring getStateName(JNIEnv *env, jint state) { 465 switch (state & JVMTI_JAVA_LANG_THREAD_STATE_MASK) { 466 case JVMTI_JAVA_LANG_THREAD_STATE_NEW: 467 return (*env)->NewStringUTF(env,"NEW"); 468 case JVMTI_JAVA_LANG_THREAD_STATE_TERMINATED: 469 return (*env)->NewStringUTF(env,"TERMINATED"); 470 case JVMTI_JAVA_LANG_THREAD_STATE_RUNNABLE: 471 return (*env)->NewStringUTF(env,"RUNNABLE"); 472 case JVMTI_JAVA_LANG_THREAD_STATE_BLOCKED: 473 return (*env)->NewStringUTF(env,"BLOCKED"); 474 case JVMTI_JAVA_LANG_THREAD_STATE_WAITING: 475 return (*env)->NewStringUTF(env, "WAITING"); 476 case JVMTI_JAVA_LANG_THREAD_STATE_TIMED_WAITING: 477 return (*env)->NewStringUTF(env,"TIMED_WAITING"); 478 } 479 // should never reach 480 assert(0); 481 return 0; 482 } 483 484 /* 485 * Class: nsk_monitoring_share_ThreadController 486 * Method: getThreadState 487 * Signature: (Ljava/lang/Thread;)Ljava/lang/Thread/State; 488 */ 489 JNIEXPORT jobject JNICALL Java_nsk_monitoring_share_ThreadController_getThreadState(JNIEnv * env,jobject obj,jobject thread)490 Java_nsk_monitoring_share_ThreadController_getThreadState(JNIEnv *env, 491 jobject obj, jobject thread){ 492 493 JavaVM *vm; 494 jvmtiEnv *jvmti; 495 jclass ThreadState; 496 jmethodID method; 497 jobject threadState; 498 jstring stateName; 499 jint state; 500 501 if(!NSK_VERIFY( 502 NSK_CPP_STUB2(GetJavaVM, env, &vm) == 0)) { 503 return NULL; 504 } 505 506 if(!NSK_VERIFY( 507 NSK_CPP_STUB3(GetEnv, vm, (void **)&jvmti, JVMTI_VERSION_1) 508 == JNI_OK)) { 509 return NULL; 510 } 511 512 if(!NSK_VERIFY( 513 NSK_CPP_STUB3(GetThreadState, jvmti, (jthread)thread, &state) 514 == JVMTI_ERROR_NONE)) { 515 return NULL; 516 } 517 518 stateName = getStateName(env, state); 519 if (!NSK_JNI_VERIFY(env, (ThreadState = NSK_CPP_STUB2(FindClass, env, "java/lang/Thread$State")) != NULL)) 520 return NULL; 521 522 if (!NSK_JNI_VERIFY(env, (method = NSK_CPP_STUB4(GetStaticMethodID, env, ThreadState, "valueOf", "(Ljava/lang/String;)Ljava/lang/Thread$State;")) != NULL)) 523 return NULL; 524 threadState = NSK_CPP_STUB4(CallStaticObjectMethod, env, ThreadState, method, stateName); 525 526 return threadState; 527 } 528 529 #ifdef __cplusplus 530 } 531 #endif 532