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