1 /*
   2  * Copyright (c) 2007, 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 #include <stdio.h>
  24 #include <stdlib.h>
  25 #include <string.h>
  26 #include <jni.h>
  27 #include <jvmti.h>
  28 #include <aod.h>
  29 #include <jvmti_aod.h>
  30 
  31 extern "C" {
  32 
  33 /*
  34  * Expected agent work scenario:
  35  *  - during initialization agent enables ThreadStart events
  36  *  - target application starts thread
  37  *  - agent receives ThreadStart event for this thread and tries to call GetThreadState for
  38  *    all VM threads, then finishes work
  39  */
  40 
  41 #define STARTED_TEST_THREAD_NAME "attach042-TestThread"
  42 
  43 static Options* options = NULL;
  44 static const char* agentName;
  45 
  46 void JNICALL threadStartHandler(jvmtiEnv *jvmti,
  47         JNIEnv* jni,
  48         jthread thread) {
  49     char startedThreadName[MAX_STRING_LENGTH];
  50 
  51     if(!nsk_jvmti_aod_getThreadName(jvmti, thread, startedThreadName)) {
  52         nsk_jvmti_aod_disableEventAndFinish(agentName, JVMTI_EVENT_THREAD_START, 0, jvmti, jni);
  53         return;
  54     }
  55 
  56     NSK_DISPLAY2("%s: ThreadStart event was received for thread '%s'\n", agentName, startedThreadName);
  57 
  58     if (!strcmp(startedThreadName, STARTED_TEST_THREAD_NAME)) {
  59         int success = 1;
  60         jint threadsCount = 0;
  61         jthread* threads = NULL;
  62         int i;
  63         int startedThreadWasFound = 0;
  64 
  65         if(!NSK_JVMTI_VERIFY(jvmti->GetAllThreads(&threadsCount, &threads))) {
  66             NSK_COMPLAIN1("%s: failed to get all threads\n", agentName);
  67             nsk_jvmti_aod_disableEventAndFinish(agentName, JVMTI_EVENT_THREAD_START, 0, jvmti, jni);
  68             return;
  69         }
  70 
  71         NSK_DISPLAY1("%s: displaying threads status:\n", agentName);
  72 
  73         for (i = 0; i < threadsCount; i++) {
  74             jint threadState;
  75             char threadName[MAX_STRING_LENGTH];
  76 
  77             if (!nsk_jvmti_aod_getThreadName(jvmti, threads[i], threadName)) {
  78                 NSK_COMPLAIN1("%s: failed to get thread name\n", agentName);
  79                 nsk_jvmti_aod_deallocate(jvmti, (unsigned char*)threads);
  80                 nsk_jvmti_aod_disableEventAndFinish(agentName, JVMTI_EVENT_THREAD_START, 0, jvmti, jni);
  81                 return;
  82             }
  83 
  84             if (!strcmp(threadName, startedThreadName)) {
  85                 startedThreadWasFound = 1;
  86             }
  87 
  88             if (!NSK_JVMTI_VERIFY(jvmti->GetThreadState(threads[i], &threadState))) {
  89                 NSK_COMPLAIN2("%s: failed to get status of thread '%s'\n", agentName, threadName);
  90                 nsk_jvmti_aod_deallocate(jvmti, (unsigned char*)threads);
  91                 nsk_jvmti_aod_disableEventAndFinish(agentName, JVMTI_EVENT_THREAD_START, 0, jvmti, jni);
  92                 return;
  93             }
  94 
  95             NSK_DISPLAY3("%s: status of '%s': %s\n", agentName, threadName, TranslateState(threadState));
  96         }
  97 
  98         nsk_jvmti_aod_deallocate(jvmti, (unsigned char*)threads);
  99 
 100         if (!startedThreadWasFound) {
 101             NSK_COMPLAIN2("%s: thread '%s' wasn't returned by GetAllThreads\n", agentName, startedThreadName);
 102             success = 0;
 103         }
 104 
 105         nsk_jvmti_aod_disableEventAndFinish(agentName, JVMTI_EVENT_THREAD_START, success, jvmti, jni);
 106     }
 107 }
 108 
 109 #ifdef STATIC_BUILD
 110 JNIEXPORT jint JNI_OnLoad_attach042Agent00(JavaVM *jvm, char *options, void *reserved) {
 111     return JNI_VERSION_1_8;
 112 }
 113 #endif
 114 
 115 JNIEXPORT jint JNICALL
 116 #ifdef STATIC_BUILD
 117 Agent_OnAttach_attach042Agent00(JavaVM *vm, char *optionsString, void *reserved)
 118 #else
 119 Agent_OnAttach(JavaVM *vm, char *optionsString, void *reserved)
 120 #endif
 121 {
 122     jvmtiEventCallbacks eventCallbacks;
 123     jvmtiEnv* jvmti;
 124     JNIEnv* jni;
 125 
 126     if (!NSK_VERIFY((options = (Options*) nsk_aod_createOptions(optionsString)) != NULL))
 127         return JNI_ERR;
 128 
 129     agentName = nsk_aod_getOptionValue(options, NSK_AOD_AGENT_NAME_OPTION);
 130 
 131     if ((jni = (JNIEnv*) nsk_aod_createJNIEnv(vm)) == NULL)
 132         return JNI_ERR;
 133 
 134     if (!NSK_VERIFY((jvmti = nsk_jvmti_createJVMTIEnv(vm, reserved)) != NULL))
 135         return JNI_ERR;
 136 
 137     memset(&eventCallbacks,0, sizeof(eventCallbacks));
 138     eventCallbacks.ThreadStart = threadStartHandler;
 139     if (!NSK_JVMTI_VERIFY(jvmti->SetEventCallbacks(&eventCallbacks, sizeof(eventCallbacks))) ) {
 140         return JNI_ERR;
 141     }
 142 
 143     if (!(nsk_jvmti_aod_enableEvent(jvmti, JVMTI_EVENT_THREAD_START))) {
 144         return JNI_ERR;
 145     }
 146 
 147     NSK_DISPLAY1("%s: initialization was done\n", agentName);
 148 
 149     if (!NSK_VERIFY(nsk_aod_agentLoaded(jni, agentName)))
 150         return JNI_ERR;
 151 
 152     return JNI_OK;
 153 }
 154 
 155 }