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