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 /* number of tested threads */
  40 #define THREADS_COUNT 6
  41 
  42 /* names of tested threads */
  43 static const char* threadsName[THREADS_COUNT] = {
  44     "threadRunning",
  45     "threadEntering",
  46     "threadWaiting",
  47     "threadSleeping",
  48     "threadRunningInterrupted",
  49     "threadRunningNative"
  50 };
  51 
  52 /* expected statuses of tested threads */
  53 #define JVMTI_THREAD_STATE_NOT_STARTED 0
  54 static jint threadsState[THREADS_COUNT] = {
  55     JVMTI_THREAD_STATE_RUNNABLE,
  56     JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER,
  57     JVMTI_THREAD_STATE_IN_OBJECT_WAIT,
  58     JVMTI_THREAD_STATE_SLEEPING,
  59     JVMTI_THREAD_STATE_RUNNABLE,
  60     JVMTI_THREAD_STATE_RUNNABLE
  61 };
  62 
  63 /* references to tested threads */
  64 static jthread threadsList[THREADS_COUNT];
  65 
  66 /* indexes of known threads */
  67 static const int interruptedThreadIndex = THREADS_COUNT - 2;
  68 static const int nativeThreadIndex = THREADS_COUNT - 1;
  69 
  70 /* ============================================================================= */
  71 
  72 /* testcase(s) */
  73 static int prepare();
  74 static int checkThreads(int suspended, const char* kind, jlong timeout);
  75 static int suspendThreadsList(int suspend);
  76 static int clean();
  77 
  78 /* ============================================================================= */
  79 
  80 /** Agent algorithm. */
  81 static void JNICALL
  82 agentProc(jvmtiEnv* jvmti, JNIEnv* agentJNI, void* arg) {
  83     jni = agentJNI;
  84 
  85     /* wait for initial sync */
  86     if (!nsk_jvmti_waitForSync(timeout))
  87         return;
  88 
  89     /* perform testcase(s) */
  90     {
  91         /* prepare data: find threads */
  92         if (!prepare()) {
  93             nsk_jvmti_setFailStatus();
  94             return;
  95         }
  96 
  97         /* testcase #1: check not suspended threads */
  98         NSK_DISPLAY0("Testcase #1: check state of not suspended threads\n");
  99         if (!checkThreads(NSK_FALSE, "not suspended", timeout))
 100             return;
 101 
 102         /* suspend threads */
 103         NSK_DISPLAY0("Suspend threads list\n");
 104         if (!suspendThreadsList(NSK_TRUE))
 105             return;
 106 
 107         /* testcase #2: check suspended threads */
 108         NSK_DISPLAY0("Testcase #2: check state of suspended threads\n");
 109         if (!checkThreads(NSK_TRUE, "suspended", 0))
 110             return;
 111 
 112         /* resume threads */
 113         NSK_DISPLAY0("Resume threads list\n");
 114         if (!suspendThreadsList(NSK_FALSE))
 115             return;
 116 
 117         /* testcase #3: check resumed threads */
 118         NSK_DISPLAY0("Testcase #3: check state of resumed threads\n");
 119         if (!checkThreads(NSK_FALSE, "resumed", 0))
 120             return;
 121 
 122         /* clean date: delete threads references */
 123         if (!clean()) {
 124             nsk_jvmti_setFailStatus();
 125             return;
 126         }
 127     }
 128 
 129     /* resume debugee after last sync */
 130     if (!nsk_jvmti_resumeSync())
 131         return;
 132 }
 133 
 134 /* ============================================================================= */
 135 
 136 /**
 137  * Prepare data:
 138  *    - clean threads list
 139  *    - get all live threads
 140  *    - get threads name
 141  *    - find tested threads
 142  *    - make global refs
 143  */
 144 static int prepare() {
 145     jthread *allThreadsList = NULL;
 146     jint allThreadsCount = 0;
 147     int found = 0;
 148     int i;
 149 
 150     NSK_DISPLAY1("Prepare: find tested threads: %d\n", THREADS_COUNT);
 151 
 152     /* clean threads list */
 153     for (i = 0; i < THREADS_COUNT; i++) {
 154         threadsList[i] = NULL;
 155     }
 156 
 157     /* get all live threads */
 158     if (!NSK_JVMTI_VERIFY(
 159             NSK_CPP_STUB3(GetAllThreads, jvmti, &allThreadsCount, &allThreadsList)))
 160         return NSK_FALSE;
 161 
 162     if (!NSK_VERIFY(allThreadsCount > 0 && allThreadsList != NULL))
 163         return NSK_FALSE;
 164 
 165     /* find tested threads */
 166     for (i = 0; i < allThreadsCount; i++) {
 167         jvmtiThreadInfo threadInfo;
 168 
 169         if (!NSK_VERIFY(allThreadsList[i] != NULL))
 170             return NSK_FALSE;
 171 
 172         /* get thread name (info) */
 173         if (!NSK_JVMTI_VERIFY(
 174                 NSK_CPP_STUB3(GetThreadInfo, jvmti, allThreadsList[i], &threadInfo)))
 175             return NSK_FALSE;
 176 
 177         /* find by name */
 178         if (threadInfo.name != NULL) {
 179             int j;
 180 
 181             for (j = 0; j < THREADS_COUNT; j++) {
 182                 if (strcmp(threadInfo.name, threadsName[j]) == 0) {
 183                     threadsList[j] = allThreadsList[i];
 184                     NSK_DISPLAY3("    thread #%d (%s): %p\n",
 185                                             j, threadInfo.name, (void*)threadsList[j]);
 186                 }
 187             }
 188         }
 189     }
 190 
 191     /* deallocate all threads list */
 192     if (!NSK_JVMTI_VERIFY(
 193             NSK_CPP_STUB2(Deallocate, jvmti, (unsigned char*)allThreadsList)))
 194         return NSK_FALSE;
 195 
 196     /* check if all tested threads found */
 197     found = 0;
 198     for (i = 0; i < THREADS_COUNT; i++) {
 199         if (threadsList[i] == NULL) {
 200             NSK_COMPLAIN2("Not found tested thread #%d (%s)\n", i, threadsName[i]);
 201         } else {
 202             found++;
 203         }
 204     }
 205 
 206     if (found < THREADS_COUNT)
 207         return NSK_FALSE;
 208 
 209     /* make global refs */
 210     for (i = 0; i < THREADS_COUNT; i++) {
 211         if (!NSK_JNI_VERIFY(jni, (threadsList[i] =
 212                 NSK_CPP_STUB2(NewGlobalRef, jni, threadsList[i])) != NULL))
 213             return NSK_FALSE;
 214     }
 215 
 216     return NSK_TRUE;
 217 }
 218 
 219 /**
 220  * Suspend or resume tested threads.
 221  */
 222 static int suspendThreadsList(int suspend) {
 223     jvmtiError results[THREADS_COUNT];
 224     const char* kind = (suspend ? "suspending" : "resuming");
 225     int i;
 226 
 227     /* suspend or resume threads list */
 228     if (suspend) {
 229         if (!NSK_JVMTI_VERIFY(
 230                 NSK_CPP_STUB4(SuspendThreadList, jvmti, THREADS_COUNT,
 231                                                     threadsList, results)))
 232             nsk_jvmti_setFailStatus();
 233     } else {
 234         if (!NSK_JVMTI_VERIFY(
 235                 NSK_CPP_STUB4(ResumeThreadList, jvmti, THREADS_COUNT,
 236                                                     threadsList, results)))
 237             nsk_jvmti_setFailStatus();
 238     }
 239 
 240     /* check results */
 241     for (i = 0; i < THREADS_COUNT; i++) {
 242         if (results[i] != JVMTI_ERROR_NONE) {
 243             NSK_COMPLAIN5("Unexpected result of %s thread #%d (%s):\n"
 244                             "#   got result: %s (%d)\n",
 245                             kind, i, threadsName[i],
 246                             TranslateError(results[i]), (int)results[i]);
 247             nsk_jvmti_setFailStatus();
 248         }
 249     }
 250 
 251     return NSK_TRUE;
 252 }
 253 
 254 /**
 255  * Testcase: check tested threads
 256  *    - get thread state and state flag
 257  *    - wait for WAITIME if state is not expected
 258  *    - check if thread state is as expected
 259  *
 260  * Returns NSK_TRUE if test may continue; or NSK_FALSE for test break.
 261  */
 262 static int checkThreads(int suspended, const char* kind, jlong timeout) {
 263     int i;
 264 
 265     /* check each thread */
 266     for (i = 0; i < THREADS_COUNT; i++) {
 267         jthread thread = threadsList[i];
 268         jint state = JVMTI_THREAD_STATE_NOT_STARTED;
 269         jlong t = 0;
 270 
 271         NSK_DISPLAY2("    thread #%d (%s):\n", i, threadsName[i]);
 272 
 273         /* wait for WAITTIME for thread to reach expected state */
 274         do {
 275             /* get thread status */
 276             if (!NSK_JVMTI_VERIFY(
 277                     NSK_CPP_STUB3(GetThreadState, jvmti, threadsList[i], &state))) {
 278                 nsk_jvmti_setFailStatus();
 279                 return NSK_TRUE;
 280             }
 281 
 282             /* break if state is NOT_STARTED as expected */
 283             if (threadsState[i] == JVMTI_THREAD_STATE_NOT_STARTED
 284                 && state == threadsState[i])
 285                 break;
 286 
 287             /* break if state is as expected */
 288             if ((state & threadsState[i]) != 0)
 289                 break;
 290 
 291             /* wait for one second */
 292             nsk_jvmti_sleep(1000);
 293             t += 1000;
 294 
 295         } while (t < timeout);
 296 
 297         /* display thread status */
 298         NSK_DISPLAY2("        state  = %s (%d)\n",
 299                                     TranslateState(state), (int)state);
 300 
 301         /* check thread status */
 302         if ((state & threadsState[i]) == 0) {
 303             if (state == JVMTI_THREAD_STATE_NOT_STARTED) {
 304                 NSK_DISPLAY1("WARNING: status of thread #%d is UNKNOWN\n", kind);
 305             } else {
 306                 NSK_COMPLAIN7("Unexpected status of %s thread #%d (%s):\n"
 307                                 "#   got status: %s (%d)\n"
 308                                 "#   expected:   %s (%d)\n",
 309                                 kind, i, threadsName[i],
 310                                 TranslateState(state), (int)state,
 311                                 TranslateState(threadsState[i]), (int)threadsState[i]);
 312                 nsk_jvmti_setFailStatus();
 313             }
 314         }
 315 
 316         /* check SUSPENDED state flag */
 317         if (suspended) {
 318             if (!(state & JVMTI_THREAD_STATE_SUSPENDED)) {
 319                 NSK_COMPLAIN5("No SUSPENDED state flag for %s thread #%d (%s):\n"
 320                                 "#    got flags: %s (%d)\n",
 321                                 kind, i, threadsName[i],
 322                                 TranslateState(state), (int)state);
 323                 nsk_jvmti_setFailStatus();
 324             }
 325         } else {
 326             if (state & JVMTI_THREAD_STATE_SUSPENDED) {
 327                 NSK_COMPLAIN5("Unexpected SUSPENDED state flag for %s thread #%d (%s):\n"
 328                                 "#   got flags: %s (%d)\n",
 329                                 kind, i, threadsName[i],
 330                                 TranslateState(state), (int)state);
 331                 nsk_jvmti_setFailStatus();
 332             }
 333         }
 334 
 335         /* check INTERRUPTED state flag */
 336         if (interruptedThreadIndex == i) {
 337             if (!(state & JVMTI_THREAD_STATE_INTERRUPTED)) {
 338                 NSK_COMPLAIN5("No INTERRUPTED state flag for %s thread #%d (%s):\n"
 339                                 "#   got flags: %s (%d)\n",
 340                                 kind, i, threadsName[i],
 341                                 TranslateState(state), (int)state);
 342                 nsk_jvmti_setFailStatus();
 343             }
 344         } else {
 345             if (state & JVMTI_THREAD_STATE_INTERRUPTED) {
 346                 NSK_COMPLAIN5("Unexpected INTERRUPTED state flag for %s thread #%d (%s):\n"
 347                                 "#   got flags: %s (%d)\n",
 348                                 kind, threadsName[i], i,
 349                                 TranslateState(state), (int)state);
 350                 nsk_jvmti_setFailStatus();
 351             }
 352         }
 353 
 354         /* check NATIVE state flag */
 355         if (nativeThreadIndex == i) {
 356             if (!(state & JVMTI_THREAD_STATE_IN_NATIVE)) {
 357                 NSK_COMPLAIN5("No NATIVE state flag for %s thread #%d (%s):\n"
 358                                 "#   got flags: %s (%d)\n",
 359                                 kind, i, threadsName[i],
 360                                 TranslateState(state), (int)state);
 361                 nsk_jvmti_setFailStatus();
 362             }
 363         } else {
 364             if (state & JVMTI_THREAD_STATE_IN_NATIVE) {
 365                 NSK_COMPLAIN5("Unexpected NATIVE state flag for %s thread #%d (%s):\n"
 366                                 "#   got flags: %s (%d)\n",
 367                                 kind, i, threadsName[i],
 368                                 TranslateState(state), (int)state);
 369                 nsk_jvmti_setFailStatus();
 370             }
 371         }
 372     }
 373 
 374     /* test may continue */
 375     return NSK_TRUE;
 376 }
 377 
 378 /**
 379  * Clean data:
 380  *   - dispose global references to tested threads
 381  */
 382 static int clean() {
 383     int i;
 384 
 385     /* dispose global references to threads */
 386     for (i = 0; i < THREADS_COUNT; i++) {
 387         NSK_TRACE(NSK_CPP_STUB2(DeleteGlobalRef, jni, threadsList[i]));
 388     }
 389 
 390     return NSK_TRUE;
 391 }
 392 
 393 /* ============================================================================= */
 394 
 395 static volatile int testedThreadRunning = NSK_FALSE;
 396 static volatile int testedThreadShouldFinish = NSK_FALSE;
 397 
 398 /** Native running method in tested thread. */
 399 JNIEXPORT void JNICALL
 400 Java_nsk_jvmti_scenarios_sampling_SP01_sp01t003ThreadRunningNative_nativeMethod(JNIEnv* jni,
 401                                                                                 jobject obj) {
 402     volatile int i = 0, n = 1000;
 403 
 404     /* run in a loop */
 405     testedThreadRunning = NSK_TRUE;
 406     while (!testedThreadShouldFinish) {
 407         if (n <= 0)
 408             n = 1000;
 409         if (i >= n)
 410             i = 0;
 411         i++;
 412     }
 413     testedThreadRunning = NSK_FALSE;
 414 }
 415 
 416 /** Aait for native method is running. */
 417 JNIEXPORT jboolean JNICALL
 418 Java_nsk_jvmti_scenarios_sampling_SP01_sp01t003ThreadRunningNative_checkReady(JNIEnv* jni,
 419                                                                             jobject obj) {
 420     while (!testedThreadRunning) {
 421         nsk_jvmti_sleep(1000);
 422     }
 423     return testedThreadRunning ? JNI_TRUE : JNI_FALSE;
 424 }
 425 
 426 /** Let native method to finish. */
 427 JNIEXPORT void JNICALL
 428 Java_nsk_jvmti_scenarios_sampling_SP01_sp01t003ThreadRunningNative_letFinish(JNIEnv* jni,
 429                                                                             jobject obj) {
 430     testedThreadShouldFinish = NSK_TRUE;
 431 }
 432 
 433 /* ============================================================================= */
 434 
 435 /** Agent library initialization. */
 436 #ifdef STATIC_BUILD
 437 JNIEXPORT jint JNICALL Agent_OnLoad_sp01t003(JavaVM *jvm, char *options, void *reserved) {
 438     return Agent_Initialize(jvm, options, reserved);
 439 }
 440 JNIEXPORT jint JNICALL Agent_OnAttach_sp01t003(JavaVM *jvm, char *options, void *reserved) {
 441     return Agent_Initialize(jvm, options, reserved);
 442 }
 443 JNIEXPORT jint JNI_OnLoad_sp01t003(JavaVM *jvm, char *options, void *reserved) {
 444     return JNI_VERSION_1_8;
 445 }
 446 #endif
 447 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
 448 
 449     /* init framework and parse options */
 450     if (!NSK_VERIFY(nsk_jvmti_parseOptions(options)))
 451         return JNI_ERR;
 452 
 453     timeout = nsk_jvmti_getWaitTime() * 60 * 1000;
 454 
 455     /* create JVMTI environment */
 456     if (!NSK_VERIFY((jvmti =
 457             nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL))
 458         return JNI_ERR;
 459 
 460     /* add specific capabilities for suspending thread */
 461     {
 462         jvmtiCapabilities suspendCaps;
 463         memset(&suspendCaps, 0, sizeof(suspendCaps));
 464         suspendCaps.can_suspend = 1;
 465         if (!NSK_JVMTI_VERIFY(
 466                 NSK_CPP_STUB2(AddCapabilities, jvmti, &suspendCaps)))
 467             return JNI_ERR;
 468     }
 469 
 470     /* register agent proc and arg */
 471     if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL)))
 472         return JNI_ERR;
 473 
 474     return JNI_OK;
 475 }
 476 
 477 /* ============================================================================= */
 478 
 479 }