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 jlong timeout = 0;
  36 
  37 /* This is how long we verify that the thread has really suspended (in ms) */
  38 static jlong verificationTime = 5 * 1000;
  39 
  40 /* constant names */
  41 #define THREAD_NAME     "TestedThread"
  42 
  43 /* constants */
  44 #define DEFAULT_THREADS_COUNT   10
  45 #define EVENTS_COUNT            1
  46 
  47 /* events list */
  48 static jvmtiEvent eventsList[EVENTS_COUNT] = {
  49     JVMTI_EVENT_THREAD_END
  50 };
  51 
  52 static int threadsCount = 0;
  53 static jthread* threads = NULL;
  54 
  55 static volatile int eventsReceived = 0;
  56 
  57 /* ============================================================================= */
  58 
  59 static int fillThreadsByName(jvmtiEnv* jvmti, JNIEnv* jni,
  60                                 const char name[], int foundCount, jthread foundThreads[]);
  61 
  62 /** Agent algorithm. */
  63 static void JNICALL
  64 agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) {
  65 
  66     NSK_DISPLAY0("Wait for threads to start\n");
  67     if (!nsk_jvmti_waitForSync(timeout))
  68         return;
  69 
  70     /* perform testing */
  71     {
  72         jvmtiError* results = NULL;
  73         int i;
  74 
  75         NSK_DISPLAY1("Allocate threads array: %d threads\n", threadsCount);
  76         if (!NSK_JVMTI_VERIFY(
  77                 NSK_CPP_STUB3(Allocate, jvmti, (threadsCount * sizeof(jthread)),
  78                                                 (unsigned char**)&threads))) {
  79             nsk_jvmti_setFailStatus();
  80             return;
  81         }
  82         NSK_DISPLAY1("  ... allocated array: %p\n", (void*)threads);
  83 
  84         NSK_DISPLAY1("Allocate results array: %d threads\n", threadsCount);
  85         if (!NSK_JVMTI_VERIFY(
  86                 NSK_CPP_STUB3(Allocate, jvmti, (threadsCount * sizeof(jvmtiError)),
  87                                                 (unsigned char**)&results))) {
  88             nsk_jvmti_setFailStatus();
  89             return;
  90         }
  91         NSK_DISPLAY1("  ... allocated array: %p\n", (void*)threads);
  92 
  93         NSK_DISPLAY1("Find threads: %d threads\n", threadsCount);
  94         if (!NSK_VERIFY(fillThreadsByName(jvmti, jni, THREAD_NAME, threadsCount, threads)))
  95             return;
  96 
  97         NSK_DISPLAY0("Suspend threads list\n");
  98         if (!NSK_JVMTI_VERIFY(
  99                 NSK_CPP_STUB4(SuspendThreadList, jvmti, threadsCount, threads, results))) {
 100             nsk_jvmti_setFailStatus();
 101             return;
 102         }
 103 
 104         NSK_DISPLAY0("Check threads results:\n");
 105         for (i = 0; i < threadsCount; i++) {
 106             NSK_DISPLAY3("  ... thread #%d: %s (%d)\n",
 107                                 i, TranslateError(results[i]), (int)results[i]);
 108             if (!NSK_JVMTI_VERIFY(results[i]))
 109                 nsk_jvmti_setFailStatus();
 110         }
 111 
 112         eventsReceived = 0;
 113         NSK_DISPLAY1("Enable event: %s\n", "THREAD_END");
 114         if (!nsk_jvmti_enableEvents(JVMTI_ENABLE, EVENTS_COUNT, eventsList, NULL))
 115             return;
 116 
 117         NSK_DISPLAY0("Let threads to run and finish\n");
 118         if (!nsk_jvmti_resumeSync())
 119             return;
 120 
 121         NSK_DISPLAY1("Check that THREAD_END event NOT received for timeout: %ld ms\n", (long)verificationTime);
 122         {
 123             jlong delta = 1000;
 124             jlong time;
 125             for (time = 0; time < verificationTime; time += delta) {
 126                 if (eventsReceived > 0) {
 127                     NSK_COMPLAIN1("Some threads ran and finished after suspension: %d threads\n",
 128                                                                             eventsReceived);
 129                     nsk_jvmti_setFailStatus();
 130                     break;
 131                 }
 132                 nsk_jvmti_sleep(delta);
 133             }
 134         }
 135 
 136         NSK_DISPLAY1("Disable event: %s\n", "THREAD_END");
 137         if (!nsk_jvmti_enableEvents(JVMTI_DISABLE, EVENTS_COUNT, eventsList, NULL))
 138             return;
 139 
 140         NSK_DISPLAY0("Resume threads list\n");
 141         if (!NSK_JVMTI_VERIFY(
 142                 NSK_CPP_STUB4(ResumeThreadList, jvmti, threadsCount, threads, results))) {
 143             nsk_jvmti_setFailStatus();
 144             return;
 145         }
 146 
 147         NSK_DISPLAY0("Wait for thread to finish\n");
 148         if (!nsk_jvmti_waitForSync(timeout))
 149             return;
 150 
 151         NSK_DISPLAY0("Delete threads references\n");
 152         for (i = 0; i < threadsCount; i++) {
 153             if (threads[i] != NULL)
 154                 NSK_TRACE(NSK_CPP_STUB2(DeleteGlobalRef, jni, threads[i]));
 155         }
 156 
 157         NSK_DISPLAY1("Deallocate threads array: %p\n", (void*)threads);
 158         if (!NSK_JVMTI_VERIFY(
 159                 NSK_CPP_STUB2(Deallocate, jvmti, (unsigned char*)threads))) {
 160             nsk_jvmti_setFailStatus();
 161         }
 162 
 163         NSK_DISPLAY1("Deallocate results array: %p\n", (void*)results);
 164         if (!NSK_JVMTI_VERIFY(
 165                 NSK_CPP_STUB2(Deallocate, jvmti, (unsigned char*)results))) {
 166             nsk_jvmti_setFailStatus();
 167         }
 168     }
 169 
 170     NSK_DISPLAY0("Let debugee to finish\n");
 171     if (!nsk_jvmti_resumeSync())
 172         return;
 173 }
 174 
 175 /* ============================================================================= */
 176 
 177 /** Find threads whose name starts with specified name prefix. */
 178 static int fillThreadsByName(jvmtiEnv* jvmti, JNIEnv* jni,
 179                             const char name[], int foundCount, jthread foundThreads[]) {
 180     jint count = 0;
 181     jthread* threads = NULL;
 182 
 183     size_t len = strlen(name);
 184     int found = 0;
 185     int i;
 186 
 187     for (i = 0; i < foundCount; i++) {
 188         foundThreads[i] = NULL;
 189     }
 190 
 191     if (!NSK_JVMTI_VERIFY(
 192             NSK_CPP_STUB3(GetAllThreads, jvmti, &count, &threads))) {
 193         nsk_jvmti_setFailStatus();
 194         return NSK_FALSE;
 195     }
 196 
 197     found = 0;
 198     for (i = 0; i < count; i++) {
 199         jvmtiThreadInfo info;
 200 
 201         if (!NSK_JVMTI_VERIFY(
 202                 NSK_CPP_STUB3(GetThreadInfo, jvmti, threads[i], &info))) {
 203             nsk_jvmti_setFailStatus();
 204             break;
 205         }
 206 
 207         if (info.name != NULL && strncmp(name, info.name, len) == 0) {
 208             NSK_DISPLAY3("  ... found thread #%d: %p (%s)\n",
 209                                     found, threads[i], info.name);
 210             if (found < foundCount)
 211                 foundThreads[found] = threads[i];
 212             found++;
 213         }
 214 
 215     }
 216 
 217     if (!NSK_JVMTI_VERIFY(
 218                 NSK_CPP_STUB2(Deallocate, jvmti, (unsigned char*)threads))) {
 219         nsk_jvmti_setFailStatus();
 220         return NSK_FALSE;
 221     }
 222 
 223     if (found != foundCount) {
 224         NSK_COMPLAIN3("Unexpected number of tested threads found:\n"
 225                       "#   name:     %s\n"
 226                       "#   found:    %d\n"
 227                       "#   expected: %d\n",
 228                       name, found, foundCount);
 229         nsk_jvmti_setFailStatus();
 230         return NSK_FALSE;
 231     }
 232 
 233     NSK_DISPLAY1("Make global references for threads: %d threads\n", foundCount);
 234     for (i = 0; i < foundCount; i++) {
 235         if (!NSK_JNI_VERIFY(jni, (foundThreads[i] = (jthread)
 236                     NSK_CPP_STUB2(NewGlobalRef, jni, foundThreads[i])) != NULL)) {
 237             nsk_jvmti_setFailStatus();
 238             return NSK_FALSE;
 239         }
 240         NSK_DISPLAY2("  ... thread #%d: %p\n", i, foundThreads[i]);
 241     }
 242 
 243     return NSK_TRUE;
 244 }
 245 
 246 /* ============================================================================= */
 247 
 248 /** THREAD_END callback. */
 249 JNIEXPORT void JNICALL
 250 callbackThreadEnd(jvmtiEnv* jvmti, JNIEnv* jni, jthread thread) {
 251     int i;
 252 
 253     /* check if event is for tested thread */
 254     for (i = 0; i < threadsCount; i++) {
 255         if (thread != NULL &&
 256                 NSK_CPP_STUB3(IsSameObject, jni, threads[i], thread)) {
 257             NSK_DISPLAY2("  ... received THREAD_END event for thread #%d: %p\n",
 258                                                                     i, (void*)thread);
 259             eventsReceived++;
 260             return;
 261         }
 262     }
 263     NSK_DISPLAY1("  ... received THREAD_END event for unknown thread: %p\n", (void*)thread);
 264 }
 265 
 266 /* ============================================================================= */
 267 
 268 /** Agent library initialization. */
 269 #ifdef STATIC_BUILD
 270 JNIEXPORT jint JNICALL Agent_OnLoad_suspendthrdlst002(JavaVM *jvm, char *options, void *reserved) {
 271     return Agent_Initialize(jvm, options, reserved);
 272 }
 273 JNIEXPORT jint JNICALL Agent_OnAttach_suspendthrdlst002(JavaVM *jvm, char *options, void *reserved) {
 274     return Agent_Initialize(jvm, options, reserved);
 275 }
 276 JNIEXPORT jint JNI_OnLoad_suspendthrdlst002(JavaVM *jvm, char *options, void *reserved) {
 277     return JNI_VERSION_1_8;
 278 }
 279 #endif
 280 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
 281     jvmtiEnv* jvmti = NULL;
 282 
 283     /* init framework and parse options */
 284     if (!NSK_VERIFY(nsk_jvmti_parseOptions(options)))
 285         return JNI_ERR;
 286 
 287     timeout = nsk_jvmti_getWaitTime() * 60 * 1000;
 288 
 289     /* get options */
 290     threadsCount = nsk_jvmti_findOptionIntValue("threads", DEFAULT_THREADS_COUNT);
 291     if (!NSK_VERIFY(threadsCount > 0))
 292         return JNI_ERR;
 293 
 294     /* create JVMTI environment */
 295     if (!NSK_VERIFY((jvmti =
 296             nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL))
 297         return JNI_ERR;
 298 
 299     /* add specific capabilities for suspending thread */
 300     {
 301         jvmtiCapabilities suspendCaps;
 302         memset(&suspendCaps, 0, sizeof(suspendCaps));
 303         suspendCaps.can_suspend = 1;
 304         if (!NSK_JVMTI_VERIFY(
 305                 NSK_CPP_STUB2(AddCapabilities, jvmti, &suspendCaps)))
 306             return JNI_ERR;
 307     }
 308 
 309     /* set callbacks for THREAD_END event */
 310     {
 311         jvmtiEventCallbacks callbacks;
 312         memset(&callbacks, 0, sizeof(callbacks));
 313         callbacks.ThreadEnd = callbackThreadEnd;
 314         if (!NSK_JVMTI_VERIFY(
 315                 NSK_CPP_STUB3(SetEventCallbacks, jvmti, &callbacks, sizeof(callbacks))))
 316         return JNI_ERR;
 317     }
 318 
 319     /* register agent proc and arg */
 320     if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL)))
 321         return JNI_ERR;
 322 
 323     return JNI_OK;
 324 }
 325 
 326 /* ============================================================================= */
 327 
 328 }