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 "jvmti_common.h"
 27 #include "jvmti_thread.h"
 28 
 29 extern "C" {
 30 
 31 /* ============================================================================= */
 32 
 33 /* scaffold objects */
 34 static jlong timeout = 0;
 35 
 36 /* This is how long we verify that the thread has really suspended (in ms) */
 37 static jlong verificationTime = 5 * 1000;
 38 
 39 /* constant names */
 40 #define THREAD_NAME     "TestedThread"
 41 
 42 /* constants */
 43 #define EVENTS_COUNT    1
 44 
 45 /* events list */
 46 static jvmtiEvent eventsList[EVENTS_COUNT] = {
 47     JVMTI_EVENT_THREAD_END
 48 };
 49 
 50 static volatile int eventsReceived = 0;
 51 static jthread testedThread = NULL;
 52 
 53 /* ============================================================================= */
 54 
 55 /** Agent algorithm. */
 56 static void JNICALL
 57 agentProc(jvmtiEnv *jvmti, JNIEnv *jni, void *arg) {
 58   jvmtiError err;
 59 
 60   NSK_DISPLAY0("Wait for thread to start\n");
 61   if (!nsk_jvmti_waitForSync(timeout))
 62     return;
 63 
 64   /* perform testing */
 65   {
 66     NSK_DISPLAY1("Find thread: %s\n", THREAD_NAME);
 67     testedThread = nsk_jvmti_threadByName(jvmti, jni, THREAD_NAME);
 68     if (testedThread == NULL) {
 69       return;
 70     }
 71     NSK_DISPLAY1("  ... found thread: %p\n", (void *) testedThread);
 72 
 73     eventsReceived = 0;
 74     NSK_DISPLAY1("Enable event: %s\n", "THREAD_END");
 75     nsk_jvmti_enableEvents(jvmti, jni, JVMTI_ENABLE, EVENTS_COUNT, eventsList, NULL);
 76 
 77     NSK_DISPLAY1("Suspend thread: %p\n", (void *) testedThread);
 78     err = jvmti->SuspendThread(testedThread);
 79     if (err != JVMTI_ERROR_NONE) {
 80       nsk_jvmti_setFailStatus();
 81       return;
 82     }
 83 
 84     NSK_DISPLAY0("Let thread to run and finish\n");
 85     if (!nsk_jvmti_resumeSync())
 86       return;
 87 
 88     NSK_DISPLAY1("Check that THREAD_END event NOT received for timeout: %ld ms\n", (long) verificationTime);
 89     {
 90       jlong delta = 1000;
 91       jlong time;
 92       for (time = 0; time < verificationTime; time += delta) {
 93         if (eventsReceived > 0) {
 94           NSK_COMPLAIN0("Thread ran and finished after suspension\n");
 95           nsk_jvmti_setFailStatus();
 96           break;
 97         }
 98         nsk_jvmti_sleep(delta);
 99       }
100     }
101 
102     NSK_DISPLAY1("Disable event: %s\n", "THREAD_END");
103     nsk_jvmti_enableEvents(jvmti, jni, JVMTI_DISABLE, EVENTS_COUNT, eventsList, NULL);
104 
105     NSK_DISPLAY1("Resume thread: %p\n", (void *) testedThread);
106     err = jvmti->ResumeThread(testedThread);
107     if (err != JVMTI_ERROR_NONE) {
108       nsk_jvmti_setFailStatus();
109       return;
110     }
111 
112     NSK_DISPLAY0("Wait for thread to finish\n");
113     if (!nsk_jvmti_waitForSync(timeout))
114       return;
115 
116     NSK_DISPLAY0("Delete thread reference\n");
117     jni->DeleteGlobalRef(testedThread);
118   }
119 
120   NSK_DISPLAY0("Let debugee to finish\n");
121   if (!nsk_jvmti_resumeSync())
122     return;
123 }
124 
125 /* ============================================================================= */
126 
127 /** THREAD_END callback. */
128 JNIEXPORT void JNICALL
129 callbackThreadEnd(jvmtiEnv *jvmti, JNIEnv *jni, jthread thread) {
130   /* check if event is for tested thread */
131   if (thread != NULL &&
132       jni->IsSameObject(testedThread, thread)) {
133     NSK_DISPLAY1("  ... received THREAD_END event for tested thread: %p\n", (void *) thread);
134     eventsReceived++;
135   } else {
136     NSK_DISPLAY1("  ... received THREAD_END event for unknown thread: %p\n", (void *) thread);
137   }
138 }
139 
140 /* ============================================================================= */
141 
142 jint Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
143   jvmtiEnv *jvmti = NULL;
144 
145   timeout = 60 * 1000;
146 
147   jint res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_9);
148   if (res != JNI_OK || jvmti == NULL) {
149     LOG("Wrong result of a valid call to GetEnv!\n");
150     return JNI_ERR;
151   }
152 
153   /* add specific capabilities for suspending thread */
154   {
155     jvmtiCapabilities suspendCaps;
156     memset(&suspendCaps, 0, sizeof(suspendCaps));
157     suspendCaps.can_suspend = 1;
158     if (jvmti->AddCapabilities(&suspendCaps) != JVMTI_ERROR_NONE) {
159       return JNI_ERR;
160     }
161   }
162 
163   /* set callbacks for THREAD_END event */
164   {
165     jvmtiEventCallbacks callbacks;
166     memset(&callbacks, 0, sizeof(callbacks));
167     callbacks.ThreadEnd = callbackThreadEnd;
168     jvmtiError err = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks));
169     if (err != JVMTI_ERROR_NONE) {
170       LOG("(SetEventCallbacks) unexpected error: %s (%d)\n", TranslateError(err), err);
171       return JNI_ERR;
172     }
173   }
174 
175   if (init_agent_data(jvmti, &agent_data) != JVMTI_ERROR_NONE) {
176     return JNI_ERR;
177   }
178   /* register agent proc and arg */
179   if (!nsk_jvmti_setAgentProc(agentProc, NULL)) {
180     return JNI_ERR;
181   }
182 
183   return JNI_OK;
184 }
185 
186 /* ============================================================================= */
187 
188 }