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