37 |
37 |
38 static jvmtiEnv *jvmti = NULL; |
38 static jvmtiEnv *jvmti = NULL; |
39 static jvmtiCapabilities caps; |
39 static jvmtiCapabilities caps; |
40 static jvmtiEventCallbacks callbacks; |
40 static jvmtiEventCallbacks callbacks; |
41 static jrawMonitorID access_lock; |
41 static jrawMonitorID access_lock; |
|
42 static jrawMonitorID wait_lock; |
42 static jint result = PASSED; |
43 static jint result = PASSED; |
43 static jboolean printdump = JNI_FALSE; |
|
44 static jthread thr_ptr = NULL; |
44 static jthread thr_ptr = NULL; |
|
45 |
45 static jint state[] = { |
46 static jint state[] = { |
46 JVMTI_THREAD_STATE_RUNNABLE, |
47 JVMTI_THREAD_STATE_RUNNABLE, |
47 JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER, |
48 JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER, |
48 JVMTI_THREAD_STATE_IN_OBJECT_WAIT |
49 JVMTI_THREAD_STATE_IN_OBJECT_WAIT |
49 }; |
50 }; |
50 |
51 |
51 static int entry_count = 0; |
52 static void |
52 static int entry_error_count = 0; |
53 lock(const char* func_name, jrawMonitorID lock) { |
53 static int exit_count = 0; |
54 jvmtiError err = jvmti->RawMonitorEnter(lock); |
54 static int exit_error_count = 0; |
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 |
|
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 |
|
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 |
|
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 } |
55 |
96 |
56 void JNICALL VMInit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thr) { |
97 void JNICALL VMInit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thr) { |
57 jvmtiError err; |
98 set_notification_mode("JVMTI_EVENT_THREAD_START", JVMTI_ENABLE, |
58 |
99 JVMTI_EVENT_THREAD_START, NULL); |
59 err = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, |
|
60 JVMTI_EVENT_THREAD_START, NULL); |
|
61 if (err != JVMTI_ERROR_NONE) { |
|
62 printf("Failed to enable THREAD_START event: %s (%d)\n", |
|
63 TranslateError(err), err); |
|
64 result = STATUS_FAILED; |
|
65 } |
|
66 |
|
67 if (caps.can_generate_method_entry_events) { |
|
68 err = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, |
|
69 JVMTI_EVENT_METHOD_ENTRY, NULL); |
|
70 if (err != JVMTI_ERROR_NONE) { |
|
71 printf("Failed to enable METHOD_ENTRY event: %s (%d)\n", |
|
72 TranslateError(err), err); |
|
73 result = STATUS_FAILED; |
|
74 } |
|
75 } |
|
76 |
|
77 if (caps.can_generate_method_exit_events) { |
|
78 err = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, |
|
79 JVMTI_EVENT_METHOD_EXIT, NULL); |
|
80 if (err != JVMTI_ERROR_NONE) { |
|
81 printf("Failed to enable METHOD_EXIT event: %s (%d)\n", |
|
82 TranslateError(err), err); |
|
83 result = STATUS_FAILED; |
|
84 } |
|
85 } |
|
86 } |
100 } |
87 |
101 |
88 void JNICALL |
102 void JNICALL |
89 ThreadStart(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread) { |
103 ThreadStart(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread) { |
90 jvmtiError err; |
104 jvmtiError err; |
91 jvmtiThreadInfo thrInfo; |
105 jvmtiThreadInfo thrInfo; |
92 |
106 |
93 err = jvmti_env->RawMonitorEnter(access_lock); |
107 lock("ThreadStart", access_lock); |
94 if (err != JVMTI_ERROR_NONE) { |
|
95 printf("(RawMonitorEnter#TS) unexpected error: %s (%d)\n", |
|
96 TranslateError(err), err); |
|
97 result = STATUS_FAILED; |
|
98 } |
|
99 |
108 |
100 err = jvmti_env->GetThreadInfo(thread, &thrInfo); |
109 err = jvmti_env->GetThreadInfo(thread, &thrInfo); |
101 if (err != JVMTI_ERROR_NONE) { |
110 if (err != JVMTI_ERROR_NONE) { |
102 printf("(GetThreadInfo#TS) unexpected error: %s (%d)\n", |
111 printf("(GetThreadInfo#TS) unexpected error: %s (%d)\n", |
103 TranslateError(err), err); |
112 TranslateError(err), err); |
104 result = STATUS_FAILED; |
113 result = STATUS_FAILED; |
105 } |
114 } |
106 if (thrInfo.name != NULL && strcmp(thrInfo.name, "thr1") == 0) { |
115 if (thrInfo.name != NULL && strcmp(thrInfo.name, "thr1") == 0) { |
107 thr_ptr = env->NewGlobalRef(thread); |
116 thr_ptr = env->NewGlobalRef(thread); |
108 if (printdump == JNI_TRUE) { |
117 printf(">>> ThreadStart: \"%s\", 0x%p\n", thrInfo.name, thr_ptr); |
109 printf(">>> ThreadStart: \"%s\", 0x%p\n", thrInfo.name, thr_ptr); |
118 set_notification_mode("JVMTI_EVENT_THREAD_START", JVMTI_DISABLE, |
110 } |
119 JVMTI_EVENT_THREAD_START, NULL); |
111 } |
120 } |
112 |
121 |
113 err = jvmti_env->RawMonitorExit(access_lock); |
122 unlock("ThreadStart", access_lock); |
114 if (err != JVMTI_ERROR_NONE) { |
|
115 printf("(RawMonitorExit#TS) unexpected error: %s (%d)\n", |
|
116 TranslateError(err), err); |
|
117 result = STATUS_FAILED; |
|
118 } |
|
119 } |
|
120 |
|
121 void JNICALL MethodEntry(jvmtiEnv *jvmti_env, JNIEnv *env, |
|
122 jthread thread, jmethodID mid) { |
|
123 jvmtiError err; |
|
124 jvmtiThreadInfo thrInfo; |
|
125 jint thrState; |
|
126 |
|
127 err = jvmti_env->RawMonitorEnter(access_lock); |
|
128 if (err != JVMTI_ERROR_NONE) { |
|
129 printf("(RawMonitorEnter#ME) unexpected error: %s (%d)\n", |
|
130 TranslateError(err), err); |
|
131 result = STATUS_FAILED; |
|
132 } |
|
133 |
|
134 entry_count++; |
|
135 err = jvmti_env->GetThreadState(thread, &thrState); |
|
136 if (err != JVMTI_ERROR_NONE) { |
|
137 printf("(GetThreadState#ME) unexpected error: %s (%d)\n", |
|
138 TranslateError(err), err); |
|
139 result = STATUS_FAILED; |
|
140 } |
|
141 if ((thrState & JVMTI_THREAD_STATE_RUNNABLE) == 0) { |
|
142 if (entry_error_count == 0) { |
|
143 err = jvmti_env->GetThreadInfo(thread, &thrInfo); |
|
144 if (err != JVMTI_ERROR_NONE) { |
|
145 printf("(GetThreadInfo#ME) unexpected error: %s (%d)\n", |
|
146 TranslateError(err), err); |
|
147 result = STATUS_FAILED; |
|
148 } |
|
149 printf("Wrong thread \"%s\" state on MethodEntry event:\n", |
|
150 thrInfo.name); |
|
151 printf(" expected: JVMTI_THREAD_STATE_RUNNABLE\n"); |
|
152 printf(" got: %s (%d)\n", |
|
153 TranslateState(thrState), thrState); |
|
154 } |
|
155 entry_error_count++; |
|
156 result = STATUS_FAILED; |
|
157 } |
|
158 |
|
159 err = jvmti_env->RawMonitorExit(access_lock); |
|
160 if (err != JVMTI_ERROR_NONE) { |
|
161 printf("(RawMonitorExit#ME) unexpected error: %s (%d)\n", |
|
162 TranslateError(err), err); |
|
163 result = STATUS_FAILED; |
|
164 } |
|
165 |
|
166 } |
|
167 |
|
168 void JNICALL MethodExit(jvmtiEnv *jvmti_env, JNIEnv *env, |
|
169 jthread thread, jmethodID mid, |
|
170 jboolean was_poped_by_exception, jvalue return_value) { |
|
171 jvmtiError err; |
|
172 jvmtiThreadInfo thrInfo; |
|
173 jint thrState; |
|
174 |
|
175 err = jvmti_env->RawMonitorEnter(access_lock); |
|
176 if (err != JVMTI_ERROR_NONE) { |
|
177 printf("(RawMonitorEnter#MX) unexpected error: %s (%d)\n", |
|
178 TranslateError(err), err); |
|
179 result = STATUS_FAILED; |
|
180 } |
|
181 |
|
182 exit_count++; |
|
183 err = jvmti_env->GetThreadState(thread, &thrState); |
|
184 if (err != JVMTI_ERROR_NONE) { |
|
185 printf("(GetThreadState#MX) unexpected error: %s (%d)\n", |
|
186 TranslateError(err), err); |
|
187 result = STATUS_FAILED; |
|
188 } |
|
189 if ((thrState & JVMTI_THREAD_STATE_RUNNABLE) == 0) { |
|
190 if (exit_error_count == 0) { |
|
191 err = jvmti_env->GetThreadInfo(thread, &thrInfo); |
|
192 if (err != JVMTI_ERROR_NONE) { |
|
193 printf("(GetThreadInfo#MX) unexpected error: %s (%d)\n", |
|
194 TranslateError(err), err); |
|
195 result = STATUS_FAILED; |
|
196 } |
|
197 printf("Wrong thread \"%s\" state on MethodExit event:\n", |
|
198 thrInfo.name); |
|
199 printf(" expected: JVMTI_THREAD_STATE_RUNNABLE\n"); |
|
200 printf(" got: %s (%d)\n", |
|
201 TranslateState(thrState), thrState); |
|
202 } |
|
203 exit_error_count++; |
|
204 result = STATUS_FAILED; |
|
205 } |
|
206 |
|
207 err = jvmti_env->RawMonitorExit(access_lock); |
|
208 if (err != JVMTI_ERROR_NONE) { |
|
209 printf("(RawMonitorExit#MX) unexpected error: %s (%d)\n", |
|
210 TranslateError(err), err); |
|
211 result = STATUS_FAILED; |
|
212 } |
|
213 } |
123 } |
214 |
124 |
215 #ifdef STATIC_BUILD |
125 #ifdef STATIC_BUILD |
216 JNIEXPORT jint JNICALL Agent_OnLoad_thrstat001(JavaVM *jvm, char *options, void *reserved) { |
126 JNIEXPORT jint JNICALL Agent_OnLoad_thrstat001(JavaVM *jvm, char *options, void *reserved) { |
217 return Agent_Initialize(jvm, options, reserved); |
127 return Agent_Initialize(jvm, options, reserved); |
258 return JNI_ERR; |
167 return JNI_ERR; |
259 } |
168 } |
260 |
169 |
261 err = jvmti->CreateRawMonitor("_access_lock", &access_lock); |
170 err = jvmti->CreateRawMonitor("_access_lock", &access_lock); |
262 if (err != JVMTI_ERROR_NONE) { |
171 if (err != JVMTI_ERROR_NONE) { |
263 printf("(CreateRawMonitor) unexpected error: %s (%d)\n", |
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", |
264 TranslateError(err), err); |
180 TranslateError(err), err); |
265 return JNI_ERR; |
181 return JNI_ERR; |
266 } |
182 } |
267 |
183 |
268 callbacks.VMInit = &VMInit; |
184 callbacks.VMInit = &VMInit; |
269 callbacks.ThreadStart = &ThreadStart; |
185 callbacks.ThreadStart = &ThreadStart; |
270 if (caps.can_generate_method_entry_events) { |
|
271 callbacks.MethodEntry = &MethodEntry; |
|
272 } else { |
|
273 printf("Warning: MethodEntry event is not implemented\n"); |
|
274 } |
|
275 if (caps.can_generate_method_exit_events) { |
|
276 callbacks.MethodExit = &MethodExit; |
|
277 } else { |
|
278 printf("Warning: MethodExit event is not implemented\n"); |
|
279 } |
|
280 err = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)); |
186 err = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)); |
281 if (err != JVMTI_ERROR_NONE) { |
187 if (err != JVMTI_ERROR_NONE) { |
282 printf("(SetEventCallbacks) unexpected error: %s (%d)\n", |
188 printf("(SetEventCallbacks) unexpected error: %s (%d)\n", |
283 TranslateError(err), err); |
189 TranslateError(err), err); |
284 return JNI_ERR; |
190 return JNI_ERR; |
285 } |
191 } |
286 |
192 |
287 err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, |
193 set_notification_mode("JVMTI_EVENT_VM_INIT", JVMTI_ENABLE, |
288 JVMTI_EVENT_VM_INIT, NULL); |
194 JVMTI_EVENT_VM_INIT, NULL); |
289 if (err != JVMTI_ERROR_NONE) { |
195 |
290 printf("Failed to enable VM_INIT event: %s (%d)\n", |
196 printf("Agent_Initialize finished\n\n"); |
291 TranslateError(err), err); |
|
292 result = STATUS_FAILED; |
|
293 } |
|
294 |
|
295 return JNI_OK; |
197 return JNI_OK; |
296 } |
198 } |
297 |
199 |
298 JNIEXPORT void JNICALL |
200 JNIEXPORT void JNICALL |
299 Java_nsk_jvmti_GetThreadState_thrstat001_checkStatus(JNIEnv *env, |
201 Java_nsk_jvmti_GetThreadState_thrstat001_checkStatus(JNIEnv *env, |
300 jclass cls, jint statInd) { |
202 jclass cls, jint statInd) { |
301 jvmtiError err; |
203 jvmtiError err; |
302 jrawMonitorID wait_lock; |
|
303 jint thrState; |
204 jint thrState; |
304 jint millis; |
205 jint millis; |
305 |
206 |
|
207 printf("native method checkStatus started\n"); |
306 if (jvmti == NULL) { |
208 if (jvmti == NULL) { |
307 printf("JVMTI client was not properly loaded!\n"); |
209 printf("JVMTI client was not properly loaded!\n"); |
308 result = STATUS_FAILED; |
210 result = STATUS_FAILED; |
309 return; |
211 return; |
310 } |
212 } |
314 result = STATUS_FAILED; |
216 result = STATUS_FAILED; |
315 return; |
217 return; |
316 } |
218 } |
317 |
219 |
318 /* wait until thread gets an expected state */ |
220 /* wait until thread gets an expected state */ |
319 err = jvmti->CreateRawMonitor("_wait_lock", &wait_lock); |
|
320 if (err != JVMTI_ERROR_NONE) { |
|
321 printf("(CreateRawMonitor) unexpected error: %s (%d)\n", |
|
322 TranslateError(err), err); |
|
323 result = STATUS_FAILED; |
|
324 } |
|
325 for (millis = WAIT_START; millis < WAIT_TIME; millis <<= 1) { |
221 for (millis = WAIT_START; millis < WAIT_TIME; millis <<= 1) { |
326 err = jvmti->GetThreadState(thr_ptr, &thrState); |
222 err = jvmti->GetThreadState(thr_ptr, &thrState); |
327 if (err != JVMTI_ERROR_NONE) { |
223 if (err != JVMTI_ERROR_NONE) { |
328 printf("(GetThreadState#%d) unexpected error: %s (%d)\n", |
224 printf("(GetThreadState#%d) unexpected error: %s (%d)\n", |
329 statInd, TranslateError(err), err); |
225 statInd, TranslateError(err), err); |
330 result = STATUS_FAILED; |
226 result = STATUS_FAILED; |
331 } |
227 } |
332 if ((thrState & state[statInd]) != 0) { |
228 if ((thrState & state[statInd]) != 0) { |
333 break; |
229 break; |
334 } |
230 } |
335 err = jvmti->RawMonitorEnter(wait_lock); |
231 lock("checkStatus", wait_lock); |
336 if (err != JVMTI_ERROR_NONE) { |
232 wait("checkStatus", wait_lock, millis); |
337 printf("(RawMonitorEnter) unexpected error: %s (%d)\n", |
233 unlock("checkStatus", wait_lock); |
338 TranslateError(err), err); |
234 } |
339 result = STATUS_FAILED; |
235 |
340 } |
236 printf(">>> thread \"thr1\" (0x%p) state: %s (%d)\n", |
341 err = jvmti->RawMonitorWait(wait_lock, (jlong)millis); |
|
342 if (err != JVMTI_ERROR_NONE) { |
|
343 printf("(RawMonitorWait) unexpected error: %s (%d)\n", |
|
344 TranslateError(err), err); |
|
345 result = STATUS_FAILED; |
|
346 } |
|
347 err = jvmti->RawMonitorExit(wait_lock); |
|
348 if (err != JVMTI_ERROR_NONE) { |
|
349 printf("(RawMonitorExit) unexpected error: %s (%d)\n", |
|
350 TranslateError(err), err); |
|
351 result = STATUS_FAILED; |
|
352 } |
|
353 } |
|
354 err = jvmti->DestroyRawMonitor(wait_lock); |
|
355 if (err != JVMTI_ERROR_NONE) { |
|
356 printf("(DestroyRawMonitor) unexpected error: %s (%d)\n", |
|
357 TranslateError(err), err); |
|
358 result = STATUS_FAILED; |
|
359 } |
|
360 |
|
361 if (printdump == JNI_TRUE) { |
|
362 printf(">>> thread \"thr1\" (0x%p) state: %s (%d)\n", |
|
363 thr_ptr, TranslateState(thrState), thrState); |
237 thr_ptr, TranslateState(thrState), thrState); |
364 } |
|
365 |
238 |
366 if ((thrState & state[statInd]) == 0) { |
239 if ((thrState & state[statInd]) == 0) { |
367 printf("Wrong thread \"thr1\" (0x%p) state:\n", thr_ptr); |
240 printf("Wrong thread \"thr1\" (0x%p) state:\n", thr_ptr); |
368 printf(" expected: %s (%d)\n", |
241 printf(" expected: %s (%d)\n", |
369 TranslateState(state[statInd]), state[statInd]); |
242 TranslateState(state[statInd]), state[statInd]); |
370 printf(" actual: %s (%d)\n", |
243 printf(" actual: %s (%d)\n", |
371 TranslateState(thrState), thrState); |
244 TranslateState(thrState), thrState); |
372 result = STATUS_FAILED; |
245 result = STATUS_FAILED; |
373 } |
246 } |
|
247 printf("native method checkStatus finished\n\n"); |
374 } |
248 } |
375 |
249 |
376 JNIEXPORT jint JNICALL |
250 JNIEXPORT jint JNICALL |
377 Java_nsk_jvmti_GetThreadState_thrstat001_getRes(JNIEnv *env, jclass cls) { |
251 Java_nsk_jvmti_GetThreadState_thrstat001_getRes(JNIEnv *env, jclass cls) { |
378 jvmtiError err; |
252 printf("native method getRes: result: %d\n\n", result); |
379 |
|
380 err = jvmti->SetEventNotificationMode(JVMTI_DISABLE, |
|
381 JVMTI_EVENT_THREAD_START, NULL); |
|
382 if (err != JVMTI_ERROR_NONE) { |
|
383 printf("Failed to disable THREAD_START event: %s (%d)\n", |
|
384 TranslateError(err), err); |
|
385 result = STATUS_FAILED; |
|
386 } |
|
387 |
|
388 if (caps.can_generate_method_entry_events) { |
|
389 err = jvmti->SetEventNotificationMode(JVMTI_DISABLE, |
|
390 JVMTI_EVENT_METHOD_ENTRY, NULL); |
|
391 if (err != JVMTI_ERROR_NONE) { |
|
392 printf("Failed to disable METHOD_ENTRY event: %s (%d)\n", |
|
393 TranslateError(err), err); |
|
394 result = STATUS_FAILED; |
|
395 } |
|
396 } |
|
397 |
|
398 if (caps.can_generate_method_exit_events) { |
|
399 err = jvmti->SetEventNotificationMode(JVMTI_DISABLE, |
|
400 JVMTI_EVENT_METHOD_EXIT, NULL); |
|
401 if (err != JVMTI_ERROR_NONE) { |
|
402 printf("Failed to disable METHOD_EXIT event: %s (%d)\n", |
|
403 TranslateError(err), err); |
|
404 result = STATUS_FAILED; |
|
405 } |
|
406 } |
|
407 |
|
408 if (printdump == JNI_TRUE) { |
|
409 printf(">>> total number of method entry events = %d\n", entry_count); |
|
410 printf(">>> total number of method exit events = %d\n", exit_count); |
|
411 } |
|
412 |
|
413 if (entry_error_count != 0) { |
|
414 printf("Total number of errors on METHOD_ENTRY: %d of %d events\n", |
|
415 entry_error_count, entry_count); |
|
416 } |
|
417 |
|
418 if (exit_error_count != 0) { |
|
419 printf("Total number of errors on METHOD_EXIT: %d of %d events\n", |
|
420 exit_error_count, exit_count); |
|
421 } |
|
422 |
|
423 return result; |
253 return result; |
424 } |
254 } |
425 |
255 |
426 } |
256 } |