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 }