1 /*
2  * Copyright (c) 2004, 2019, 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 #define WAIT_TIME (2*60*1000)
37 
38 static jvmtiEnv *jvmti = NULL;
39 static jvmtiCapabilities caps;
40 static jvmtiEventCallbacks callbacks;
41 static jrawMonitorID access_lock;
42 static jrawMonitorID wait_lock;
43 static jint result = PASSED;
44 static jthread thr_ptr = NULL;
45 
46 static jint state[] = {
47     JVMTI_THREAD_STATE_RUNNABLE,
48     JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER,
49     JVMTI_THREAD_STATE_IN_OBJECT_WAIT
50 };
51 
52 static void
lock(const char * func_name,jrawMonitorID lock)53 lock(const char* func_name, jrawMonitorID lock) {
54     jvmtiError err = jvmti->RawMonitorEnter(lock);
55     if (err != JVMTI_ERROR_NONE) {
56         printf("%s: unexpected error in RawMonitorEnter: %s (%d)\n",
57                func_name, TranslateError(err), err);
58         result = STATUS_FAILED;
59     }
60 }
61 
62 static void
unlock(const char * func_name,jrawMonitorID lock)63 unlock(const char* func_name, jrawMonitorID lock) {
64     jvmtiError err = jvmti->RawMonitorExit(lock);
65     if (err != JVMTI_ERROR_NONE) {
66         printf("%s: unexpected error in RawMonitorExit: %s (%d)\n",
67                func_name, TranslateError(err), err);
68         result = STATUS_FAILED;
69     }
70 }
71 
72 static void
wait(const char * func_name,jrawMonitorID lock,jint millis)73 wait(const char* func_name, jrawMonitorID lock, jint millis) {
74     jvmtiError err = jvmti->RawMonitorWait(lock, (jlong)millis);
75     if (err != JVMTI_ERROR_NONE) {
76         printf("%s: unexpected error in RawMonitorWait: %s (%d)\n",
77                func_name, TranslateError(err), err);
78         result = STATUS_FAILED;
79     }
80 }
81 
82 static void
set_notification_mode(const char * event_name,jvmtiEventMode mode,jvmtiEvent event_type,jthread event_thread)83 set_notification_mode(const char* event_name,
84                       jvmtiEventMode mode,
85                       jvmtiEvent event_type,
86                       jthread event_thread) {
87     const char* action = (mode == JVMTI_ENABLE) ? "enable" : "disable";
88     jvmtiError err = jvmti->SetEventNotificationMode(mode, event_type, event_thread);
89 
90     if (err != JVMTI_ERROR_NONE) {
91         printf("Failed to %s %s event: %s (%d)\n",
92                action, event_name, TranslateError(err), err);
93         result = STATUS_FAILED;
94     }
95 }
96 
VMInit(jvmtiEnv * jvmti_env,JNIEnv * env,jthread thr)97 void JNICALL VMInit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thr) {
98     set_notification_mode("JVMTI_EVENT_THREAD_START", JVMTI_ENABLE,
99                           JVMTI_EVENT_THREAD_START, NULL);
100 }
101 
102 void JNICALL
ThreadStart(jvmtiEnv * jvmti_env,JNIEnv * env,jthread thread)103 ThreadStart(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread) {
104     jvmtiError err;
105     jvmtiThreadInfo thrInfo;
106 
107     lock("ThreadStart", access_lock);
108 
109     err = jvmti_env->GetThreadInfo(thread, &thrInfo);
110     if (err != JVMTI_ERROR_NONE) {
111         printf("(GetThreadInfo#TS) unexpected error: %s (%d)\n",
112                TranslateError(err), err);
113         result = STATUS_FAILED;
114     }
115     if (thrInfo.name != NULL && strcmp(thrInfo.name, "thr1") == 0) {
116         thr_ptr = env->NewGlobalRef(thread);
117         printf(">>> ThreadStart: \"%s\", 0x%p\n", thrInfo.name, thr_ptr);
118         set_notification_mode("JVMTI_EVENT_THREAD_START", JVMTI_DISABLE,
119                               JVMTI_EVENT_THREAD_START, NULL);
120     }
121 
122     unlock("ThreadStart", access_lock);
123 }
124 
125 #ifdef STATIC_BUILD
Agent_OnLoad_thrstat001(JavaVM * jvm,char * options,void * reserved)126 JNIEXPORT jint JNICALL Agent_OnLoad_thrstat001(JavaVM *jvm, char *options, void *reserved) {
127     return Agent_Initialize(jvm, options, reserved);
128 }
Agent_OnAttach_thrstat001(JavaVM * jvm,char * options,void * reserved)129 JNIEXPORT jint JNICALL Agent_OnAttach_thrstat001(JavaVM *jvm, char *options, void *reserved) {
130     return Agent_Initialize(jvm, options, reserved);
131 }
JNI_OnLoad_thrstat001(JavaVM * jvm,char * options,void * reserved)132 JNIEXPORT jint JNI_OnLoad_thrstat001(JavaVM *jvm, char *options, void *reserved) {
133     return JNI_VERSION_1_8;
134 }
135 #endif
136 
Agent_Initialize(JavaVM * jvm,char * options,void * reserved)137 jint  Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
138     jint res;
139     jvmtiError err;
140 
141     printf("Agent_Initialize started\n");
142 
143     res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1);
144     if (res != JNI_OK || jvmti == NULL) {
145         printf("Wrong result of a valid call to GetEnv!\n");
146         return JNI_ERR;
147     }
148 
149     err = jvmti->GetPotentialCapabilities(&caps);
150     if (err != JVMTI_ERROR_NONE) {
151         printf("(GetPotentialCapabilities) unexpected error: %s (%d)\n",
152                TranslateError(err), err);
153         return JNI_ERR;
154     }
155 
156     err = jvmti->AddCapabilities(&caps);
157     if (err != JVMTI_ERROR_NONE) {
158         printf("(AddCapabilities) unexpected error: %s (%d)\n",
159                TranslateError(err), err);
160         return JNI_ERR;
161     }
162 
163     err = jvmti->GetCapabilities(&caps);
164     if (err != JVMTI_ERROR_NONE) {
165         printf("(GetCapabilities) unexpected error: %s (%d)\n",
166                TranslateError(err), err);
167         return JNI_ERR;
168     }
169 
170     err = jvmti->CreateRawMonitor("_access_lock", &access_lock);
171     if (err != JVMTI_ERROR_NONE) {
172         printf("(CreateRawMonitor)#access_lock unexpected error: %s (%d)\n",
173                TranslateError(err), err);
174         return JNI_ERR;
175     }
176 
177     err = jvmti->CreateRawMonitor("_wait_lock", &wait_lock);
178     if (err != JVMTI_ERROR_NONE) {
179         printf("(CreateRawMonitor#wait_lock) unexpected error: %s (%d)\n",
180                TranslateError(err), err);
181         return JNI_ERR;
182     }
183 
184     callbacks.VMInit = &VMInit;
185     callbacks.ThreadStart = &ThreadStart;
186     err = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks));
187     if (err != JVMTI_ERROR_NONE) {
188         printf("(SetEventCallbacks) unexpected error: %s (%d)\n",
189                TranslateError(err), err);
190         return JNI_ERR;
191     }
192 
193     set_notification_mode("JVMTI_EVENT_VM_INIT", JVMTI_ENABLE,
194                           JVMTI_EVENT_VM_INIT, NULL);
195 
196     printf("Agent_Initialize finished\n\n");
197     return JNI_OK;
198 }
199 
200 JNIEXPORT void JNICALL
Java_nsk_jvmti_GetThreadState_thrstat001_checkStatus(JNIEnv * env,jclass cls,jint statInd)201 Java_nsk_jvmti_GetThreadState_thrstat001_checkStatus(JNIEnv *env,
202         jclass cls, jint statInd) {
203     jvmtiError err;
204     jint thrState;
205     jint millis;
206 
207     printf("native method checkStatus started\n");
208     if (jvmti == NULL) {
209         printf("JVMTI client was not properly loaded!\n");
210         result = STATUS_FAILED;
211         return;
212     }
213 
214     if (thr_ptr == NULL) {
215         printf("Missing thread \"thr1\" start event\n");
216         result = STATUS_FAILED;
217         return;
218     }
219 
220     /* wait until thread gets an expected state */
221     for (millis = WAIT_START; millis < WAIT_TIME; millis <<= 1) {
222         err = jvmti->GetThreadState(thr_ptr, &thrState);
223         if (err != JVMTI_ERROR_NONE) {
224             printf("(GetThreadState#%d) unexpected error: %s (%d)\n",
225                 statInd, TranslateError(err), err);
226             result = STATUS_FAILED;
227         }
228         if ((thrState & state[statInd]) != 0) {
229             break;
230         }
231         lock("checkStatus", wait_lock);
232         wait("checkStatus", wait_lock, millis);
233         unlock("checkStatus", wait_lock);
234     }
235 
236     printf(">>> thread \"thr1\" (0x%p) state: %s (%d)\n",
237             thr_ptr, TranslateState(thrState), thrState);
238 
239     if ((thrState & state[statInd]) == 0) {
240         printf("Wrong thread \"thr1\" (0x%p) state:\n", thr_ptr);
241         printf("    expected: %s (%d)\n",
242             TranslateState(state[statInd]), state[statInd]);
243         printf("      actual: %s (%d)\n",
244             TranslateState(thrState), thrState);
245         result = STATUS_FAILED;
246     }
247     printf("native method checkStatus finished\n\n");
248 }
249 
250 JNIEXPORT jint JNICALL
Java_nsk_jvmti_GetThreadState_thrstat001_getRes(JNIEnv * env,jclass cls)251 Java_nsk_jvmti_GetThreadState_thrstat001_getRes(JNIEnv *env, jclass cls) {
252     printf("native method getRes: result: %d\n\n", result);
253     return result;
254 }
255 
256 }
257