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