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