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