1 /*
2  * Copyright (c) 2004, 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 <stdio.h>
25 #include <string.h>
26 #include "jvmti.h"
27 #include "agent_common.h"
28 #include "JVMTITools.h"
29 
30 extern "C" {
31 
32 
33 #define PASSED  0
34 #define STATUS_FAILED  2
35 #define WAIT_START 100
36 
37 static jvmtiEnv *jvmti = NULL;
38 static jvmtiCapabilities caps;
39 static jvmtiEventCallbacks callbacks;
40 static jrawMonitorID access_lock, wait_lock;
41 static jint result = PASSED;
42 static jboolean printdump = JNI_FALSE;
43 static jthread thr_ptr = NULL;
44 static jint wait_time = 0;
45 static jint state[] = {
46     JVMTI_THREAD_STATE_RUNNABLE,
47     JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER,
48     JVMTI_THREAD_STATE_IN_OBJECT_WAIT
49 };
50 
printStateFlags(jint flags)51 void printStateFlags(jint flags) {
52     if (flags & JVMTI_THREAD_STATE_SUSPENDED)
53         printf(" JVMTI_THREAD_STATE_SUSPENDED");
54     if (flags & JVMTI_THREAD_STATE_INTERRUPTED)
55         printf(" JVMTI_THREAD_STATE_INTERRUPTED");
56     if (flags & JVMTI_THREAD_STATE_IN_NATIVE)
57         printf(" JVMTI_THREAD_STATE_IN_NATIVE");
58     printf(" (0x%0x)\n", flags);
59 }
60 
VMInit(jvmtiEnv * jvmti_env,JNIEnv * env,jthread thr)61 void JNICALL VMInit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thr) {
62     jvmtiError err;
63 
64     err = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
65         JVMTI_EVENT_THREAD_START, NULL);
66     if (err != JVMTI_ERROR_NONE) {
67         printf("Failed to enable THREAD_START event: %s (%d)\n",
68                TranslateError(err), err);
69         result = STATUS_FAILED;
70     }
71 }
72 
73 void JNICALL
ThreadStart(jvmtiEnv * jvmti_env,JNIEnv * env,jthread thread)74 ThreadStart(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread) {
75     jvmtiThreadInfo thrInfo;
76     jvmtiError err;
77 
78     err = jvmti_env->RawMonitorEnter(access_lock);
79     if (err != JVMTI_ERROR_NONE) {
80         printf("(RawMonitorEnter) unexpected error: %s (%d)\n",
81                TranslateError(err), err);
82         result = STATUS_FAILED;
83     }
84 
85     err = jvmti_env->GetThreadInfo(thread, &thrInfo);
86     if (err != JVMTI_ERROR_NONE) {
87         printf("(GetThreadInfo) unexpected error: %s (%d)\n",
88                TranslateError(err), err);
89         result = STATUS_FAILED;
90     }
91     if (thrInfo.name != NULL && strcmp(thrInfo.name, "thr1") == 0) {
92         thr_ptr = env->NewGlobalRef(thread);
93         if (printdump == JNI_TRUE) {
94             printf(">>> ThreadStart: \"%s\", 0x%p\n", thrInfo.name, thr_ptr);
95         }
96     }
97 
98     err = jvmti_env->RawMonitorExit(access_lock);
99     if (err != JVMTI_ERROR_NONE) {
100         printf("(RawMonitorExit) unexpected error: %s (%d)\n",
101                TranslateError(err), err);
102         result = STATUS_FAILED;
103     }
104 }
105 
106 #ifdef STATIC_BUILD
Agent_OnLoad_thrstat002(JavaVM * jvm,char * options,void * reserved)107 JNIEXPORT jint JNICALL Agent_OnLoad_thrstat002(JavaVM *jvm, char *options, void *reserved) {
108     return Agent_Initialize(jvm, options, reserved);
109 }
Agent_OnAttach_thrstat002(JavaVM * jvm,char * options,void * reserved)110 JNIEXPORT jint JNICALL Agent_OnAttach_thrstat002(JavaVM *jvm, char *options, void *reserved) {
111     return Agent_Initialize(jvm, options, reserved);
112 }
JNI_OnLoad_thrstat002(JavaVM * jvm,char * options,void * reserved)113 JNIEXPORT jint JNI_OnLoad_thrstat002(JavaVM *jvm, char *options, void *reserved) {
114     return JNI_VERSION_1_8;
115 }
116 #endif
Agent_Initialize(JavaVM * jvm,char * options,void * reserved)117 jint  Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
118     jint res;
119     jvmtiError err;
120 
121     if (options != NULL && strcmp(options, "printdump") == 0) {
122         printdump = JNI_TRUE;
123     }
124 
125     res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1);
126     if (res != JNI_OK || jvmti == NULL) {
127         printf("Wrong result of a valid call to GetEnv !\n");
128         return JNI_ERR;
129     }
130 
131     err = jvmti->GetPotentialCapabilities(&caps);
132     if (err != JVMTI_ERROR_NONE) {
133         printf("(GetPotentialCapabilities) unexpected error: %s (%d)\n",
134                TranslateError(err), err);
135         return JNI_ERR;
136     }
137 
138     err = jvmti->AddCapabilities(&caps);
139     if (err != JVMTI_ERROR_NONE) {
140         printf("(AddCapabilities) unexpected error: %s (%d)\n",
141                TranslateError(err), err);
142         return JNI_ERR;
143     }
144 
145     err = jvmti->GetCapabilities(&caps);
146     if (err != JVMTI_ERROR_NONE) {
147         printf("(GetCapabilities) unexpected error: %s (%d)\n",
148                TranslateError(err), err);
149         return JNI_ERR;
150     }
151 
152     if (!caps.can_suspend) {
153         printf("Warning: suspend/resume is not implemented\n");
154     }
155 
156     err = jvmti->CreateRawMonitor("_access_lock", &access_lock);
157     if (err != JVMTI_ERROR_NONE) {
158         printf("(CreateRawMonitor) unexpected error: %s (%d)\n",
159                TranslateError(err), err);
160         return JNI_ERR;
161     }
162 
163     err = jvmti->CreateRawMonitor("_wait_lock", &wait_lock);
164     if (err != JVMTI_ERROR_NONE) {
165         printf("(CreateRawMonitor) unexpected error: %s (%d)\n",
166                TranslateError(err), err);
167         return JNI_ERR;
168     }
169 
170     callbacks.VMInit = &VMInit;
171     callbacks.ThreadStart = &ThreadStart;
172     err = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks));
173     if (err != JVMTI_ERROR_NONE) {
174         printf("(SetEventCallbacks) unexpected error: %s (%d)\n",
175                TranslateError(err), err);
176         return JNI_ERR;
177     }
178 
179     err = jvmti->SetEventNotificationMode(JVMTI_ENABLE,
180         JVMTI_EVENT_VM_INIT, NULL);
181     if (err != JVMTI_ERROR_NONE) {
182         printf("Failed to enable VM_INIT event: %s (%d)\n",
183                TranslateError(err), err);
184         result = STATUS_FAILED;
185     }
186 
187     return JNI_OK;
188 }
189 
190 JNIEXPORT void JNICALL
Java_nsk_jvmti_GetThreadState_thrstat002_init(JNIEnv * env,jclass cls,jint waitTime)191 Java_nsk_jvmti_GetThreadState_thrstat002_init(JNIEnv *env, jclass cls,
192         jint waitTime) {
193     wait_time = waitTime * 60000;
194 }
195 
wait_for(jint millis)196 void wait_for(jint millis) {
197     jvmtiError err;
198 
199     err = jvmti->RawMonitorEnter(wait_lock);
200     if (err != JVMTI_ERROR_NONE) {
201         printf("(RawMonitorEnter#check) unexpected error: %s (%d)\n",
202                TranslateError(err), err);
203         result = STATUS_FAILED;
204     }
205     err = jvmti->RawMonitorWait(wait_lock, (jlong)millis);
206     if (err != JVMTI_ERROR_NONE) {
207         printf("(RawMonitorWait#check) unexpected error: %s (%d)\n",
208                TranslateError(err), err);
209         result = STATUS_FAILED;
210     }
211     err = jvmti->RawMonitorExit(wait_lock);
212     if (err != JVMTI_ERROR_NONE) {
213         printf("(RawMonitorExit#check) unexpected error: %s (%d)\n",
214                TranslateError(err), err);
215         result = STATUS_FAILED;
216     }
217 }
218 
219 JNIEXPORT void JNICALL
Java_nsk_jvmti_GetThreadState_thrstat002_checkStatus(JNIEnv * env,jclass cls,jint statInd,jboolean suspended)220 Java_nsk_jvmti_GetThreadState_thrstat002_checkStatus(JNIEnv *env, jclass cls,
221         jint statInd, jboolean suspended) {
222     jint thrState;
223     jint suspState = -1;
224     jint right_stat = (suspended ? JVMTI_THREAD_STATE_SUSPENDED : 0);
225     jvmtiError right_ans = (suspended ? JVMTI_ERROR_THREAD_SUSPENDED : JVMTI_ERROR_NONE);
226     const char *suspStr = (suspended ? ", suspended" : "");
227     jvmtiError err;
228     jint millis;
229     jboolean timeout_is_reached;
230     unsigned int waited_millis;
231 
232     if (jvmti == NULL) {
233         printf("JVMTI client was not properly loaded!\n");
234         result = STATUS_FAILED;
235         return;
236     }
237 
238     if (thr_ptr == NULL) {
239         printf("Missing thread \"thr1\" start event\n");
240         result = STATUS_FAILED;
241         return;
242     }
243 
244     if (!caps.can_suspend) {
245         return;
246     }
247 
248     printf("START checkStatus for \"thr1\" (0x%p%s), check state: %s\n",
249            thr_ptr, suspStr, TranslateState(state[statInd]));
250 
251     timeout_is_reached = JNI_TRUE;
252     for (millis = WAIT_START, waited_millis=0; millis < wait_time; millis <<= 1) {
253         err = jvmti->GetThreadState(thr_ptr, &thrState);
254         if (err != JVMTI_ERROR_NONE) {
255             printf("(GetThreadState#%d) unexpected error: %s (%d)\n",
256                 statInd, TranslateError(err), err);
257             result = STATUS_FAILED;
258             timeout_is_reached = JNI_FALSE;
259             break;
260         }
261         suspState = thrState & JVMTI_THREAD_STATE_SUSPENDED;
262         if (suspended || (thrState & JVMTI_THREAD_STATE_RUNNABLE) == 0 ||
263             (state[statInd] == JVMTI_THREAD_STATE_RUNNABLE)) {
264             timeout_is_reached = JNI_FALSE;
265             break;
266         }
267 
268         waited_millis += millis;
269         wait_for(millis);
270     }
271 
272     if (printdump == JNI_TRUE) {
273         printf(">>> thread \"thr1\" (0x%p) state: %s (%d)\n",
274             thr_ptr, TranslateState(thrState), thrState);
275         printf(">>>\tflags:");
276         printStateFlags(suspState);
277     }
278 
279     if (timeout_is_reached == JNI_TRUE) {
280         printf("Error: timeout (%d secs) has been reached\n", waited_millis/1000);
281     }
282     if ((thrState & state[statInd]) == 0) {
283         printf("Wrong thread \"thr1\" (0x%p%s) state:\n", thr_ptr, suspStr);
284         printf("    expected: %s (%d)\n",
285             TranslateState(state[statInd]), state[statInd]);
286         printf("      actual: %s (%d)\n",
287             TranslateState(thrState), thrState);
288         result = STATUS_FAILED;
289     }
290     if (suspState != right_stat) {
291         printf("Wrong thread \"thr1\" (0x%p%s) state flags:\n",
292                thr_ptr, suspStr);
293         printf("    expected:");
294         printStateFlags(right_stat);
295         printf("    actual:");
296         printStateFlags(suspState);
297         result = STATUS_FAILED;
298     }
299 
300     err = jvmti->SuspendThread(thr_ptr);
301     if (err != right_ans) {
302         printf("Wrong result of SuspendThread() for \"thr1\" (0x%p%s):\n",
303                thr_ptr, suspStr);
304         printf("    expected: %s (%d), actual: %s (%d)\n",
305             TranslateError(right_ans), right_ans, TranslateError(err), err);
306         result = STATUS_FAILED;
307     }
308 
309     if (!suspended) {
310         // wait till thread is not suspended
311         timeout_is_reached = JNI_TRUE;
312         for (millis = WAIT_START, waited_millis=0; millis < wait_time; millis <<= 1) {
313             waited_millis += millis;
314             wait_for(millis);
315             err = jvmti->GetThreadState(thr_ptr, &thrState);
316             if (err != JVMTI_ERROR_NONE) {
317                 printf("(GetThreadState#%d,after) unexpected error: %s (%d)\n",
318                     statInd, TranslateError(err), err);
319                 timeout_is_reached = JNI_FALSE;
320                 result = STATUS_FAILED;
321                 break;
322             }
323             suspState = thrState & JVMTI_THREAD_STATE_SUSPENDED;
324             if (suspState) {
325                 timeout_is_reached = JNI_FALSE;
326                 break;
327             }
328         }
329 
330         if (timeout_is_reached == JNI_TRUE) {
331             printf("Error: timeout (%d secs) has been reached\n", waited_millis/1000);
332         }
333         if ((thrState & state[statInd]) == 0) {
334             printf("Wrong thread \"thr1\" (0x%p) state after SuspendThread:\n",
335                 thr_ptr);
336             printf("    expected: %s (%d)\n",
337                 TranslateState(state[statInd]), state[statInd]);
338             printf("      actual: %s (%d)\n",
339                 TranslateState(thrState), thrState);
340             result = STATUS_FAILED;
341         }
342         if (suspState != JVMTI_THREAD_STATE_SUSPENDED) {
343             printf("Wrong thread \"thr1\" (0x%p) state flags", thr_ptr);
344             printf(" after SuspendThread:\n");
345             printf("    expected:");
346             printStateFlags(JVMTI_THREAD_STATE_SUSPENDED);
347             printf("    actual:");
348             printStateFlags(suspState);
349             result = STATUS_FAILED;
350         }
351         err = jvmti->ResumeThread(thr_ptr);
352         if (err != JVMTI_ERROR_NONE) {
353             printf("(ResumeThread#%d) unexpected error: %s (%d)\n",
354                 statInd, TranslateError(err), err);
355             result = STATUS_FAILED;
356         }
357     }
358 }
359 
360 JNIEXPORT jint JNICALL
Java_nsk_jvmti_GetThreadState_thrstat002_getRes(JNIEnv * env,jclass cls)361 Java_nsk_jvmti_GetThreadState_thrstat002_getRes(JNIEnv *env, jclass cls) {
362     return result;
363 }
364 
365 }
366