|
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 <stdlib.h> |
|
25 #include <string.h> |
|
26 #include "jni_tools.h" |
|
27 #include "agent_common.h" |
|
28 #include "jvmti_tools.h" |
|
29 |
|
30 #ifdef __cplusplus |
|
31 extern "C" { |
|
32 #endif |
|
33 |
|
34 /* ========================================================================== */ |
|
35 |
|
36 static const jlong EXPECTED_TIMEOUT = 1; |
|
37 /* |
|
38 * The expected timeout accuracy was already increased from 100000 to 300000. |
|
39 * Please, do not increase it anymore if the test still fails with the message: |
|
40 * "(waitedTime - waitTime) >= (EXPECTED_TIMEOUT * 1000000) - EXPECTED_TIMEOUT_ACCURACY_NS" |
|
41 */ |
|
42 static const jlong EXPECTED_TIMEOUT_ACCURACY_NS = 300000; |
|
43 |
|
44 static const jlong EXPECTED_ACCURACY = 10; |
|
45 |
|
46 /* scaffold objects */ |
|
47 static jlong timeout = 0; |
|
48 |
|
49 /* test objects */ |
|
50 static jthread thread = NULL; |
|
51 static jobject object_M = NULL; |
|
52 static volatile int waitEventsCount = 0; |
|
53 static volatile int waitedEventsCount = 0; |
|
54 static jlong waitTime = 0; |
|
55 static jlong waitThreadCpuTime = 0; |
|
56 static jlong waitedTime = 0; |
|
57 static jlong waitedThreadCpuTime = 0; |
|
58 |
|
59 /* ========================================================================== */ |
|
60 |
|
61 void JNICALL |
|
62 MonitorWait(jvmtiEnv *jvmti, JNIEnv* jni, |
|
63 jthread thr, jobject obj, jlong tout) { |
|
64 char buffer[32]; |
|
65 |
|
66 if (!NSK_VERIFY(thr != NULL)) { |
|
67 nsk_jvmti_setFailStatus(); |
|
68 return; |
|
69 } |
|
70 |
|
71 if (!NSK_VERIFY(obj != NULL)) { |
|
72 nsk_jvmti_setFailStatus(); |
|
73 return; |
|
74 } |
|
75 |
|
76 /* check if event is for tested thread and object */ |
|
77 if (NSK_CPP_STUB3(IsSameObject, jni, thread, thr) && |
|
78 NSK_CPP_STUB3(IsSameObject, jni, object_M, obj)) { |
|
79 if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3( |
|
80 GetThreadCpuTime, jvmti, thr, &waitThreadCpuTime))) { |
|
81 nsk_jvmti_setFailStatus(); |
|
82 } |
|
83 if (!NSK_JVMTI_VERIFY( |
|
84 NSK_CPP_STUB2(GetTime, jvmti, &waitTime))) { |
|
85 nsk_jvmti_setFailStatus(); |
|
86 } |
|
87 waitEventsCount++; |
|
88 NSK_DISPLAY0("MonitorWait event:\n"); |
|
89 NSK_DISPLAY3("\tthread: %p, object: %p, timeout: %s\n", |
|
90 thr, obj, jlong_to_string(tout, buffer)); |
|
91 NSK_DISPLAY1("\ttime: %s\n", |
|
92 jlong_to_string(waitTime, buffer)); |
|
93 NSK_DISPLAY1("\tthread CPU time: %s\n", |
|
94 jlong_to_string(waitThreadCpuTime, buffer)); |
|
95 |
|
96 if (!NSK_VERIFY(tout == EXPECTED_TIMEOUT)) { |
|
97 nsk_jvmti_setFailStatus(); |
|
98 } |
|
99 } |
|
100 } |
|
101 |
|
102 void JNICALL |
|
103 MonitorWaited(jvmtiEnv *jvmti, JNIEnv* jni, |
|
104 jthread thr, jobject obj, jboolean timed_out) { |
|
105 char buffer[32]; |
|
106 |
|
107 if (!NSK_VERIFY(thr != NULL)) { |
|
108 nsk_jvmti_setFailStatus(); |
|
109 return; |
|
110 } |
|
111 |
|
112 if (!NSK_VERIFY(obj != NULL)) { |
|
113 nsk_jvmti_setFailStatus(); |
|
114 return; |
|
115 } |
|
116 |
|
117 /* check if event is for tested thread and object */ |
|
118 if (NSK_CPP_STUB3(IsSameObject, jni, thread, thr) && |
|
119 NSK_CPP_STUB3(IsSameObject, jni, object_M, obj)) { |
|
120 if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3( |
|
121 GetThreadCpuTime, jvmti, thr, &waitedThreadCpuTime))) { |
|
122 nsk_jvmti_setFailStatus(); |
|
123 } |
|
124 if (!NSK_JVMTI_VERIFY( |
|
125 NSK_CPP_STUB2(GetTime, jvmti, &waitedTime))) { |
|
126 nsk_jvmti_setFailStatus(); |
|
127 } |
|
128 waitedEventsCount++; |
|
129 NSK_DISPLAY0("MonitorWaited event:\n"); |
|
130 NSK_DISPLAY3("\tthread: %p, object: %p, timed_out: %s\n", |
|
131 thr, obj, (timed_out==JNI_TRUE) ? "true" : "false"); |
|
132 NSK_DISPLAY1("\tGetTime: %s\n", |
|
133 jlong_to_string(waitedTime, buffer)); |
|
134 NSK_DISPLAY1("\tthread CPU time: %s\n", |
|
135 jlong_to_string(waitedThreadCpuTime, buffer)); |
|
136 } |
|
137 } |
|
138 |
|
139 /* ========================================================================== */ |
|
140 |
|
141 static int prepare(jvmtiEnv* jvmti, JNIEnv* jni) { |
|
142 const char* THREAD_NAME = "Debuggee Thread"; |
|
143 const char* FIELD_SIG = "Ljava/lang/Object;"; |
|
144 jvmtiThreadInfo info; |
|
145 jthread *threads = NULL; |
|
146 jint threads_count = 0; |
|
147 jfieldID field = NULL; |
|
148 jclass klass = NULL; |
|
149 int i; |
|
150 |
|
151 NSK_DISPLAY0("Prepare: find tested thread\n"); |
|
152 |
|
153 /* get all live threads */ |
|
154 if (!NSK_JVMTI_VERIFY( |
|
155 NSK_CPP_STUB3(GetAllThreads, jvmti, &threads_count, &threads))) |
|
156 return NSK_FALSE; |
|
157 |
|
158 if (!NSK_VERIFY(threads_count > 0 && threads != NULL)) |
|
159 return NSK_FALSE; |
|
160 |
|
161 /* find tested thread */ |
|
162 for (i = 0; i < threads_count; i++) { |
|
163 if (!NSK_VERIFY(threads[i] != NULL)) |
|
164 return NSK_FALSE; |
|
165 |
|
166 /* get thread information */ |
|
167 if (!NSK_JVMTI_VERIFY( |
|
168 NSK_CPP_STUB3(GetThreadInfo, jvmti, threads[i], &info))) |
|
169 return NSK_FALSE; |
|
170 |
|
171 NSK_DISPLAY3(" thread #%d (%s): %p\n", i, info.name, threads[i]); |
|
172 |
|
173 /* find by name */ |
|
174 if (info.name != NULL && (strcmp(info.name, THREAD_NAME) == 0)) { |
|
175 thread = threads[i]; |
|
176 } |
|
177 |
|
178 if (info.name != NULL) { |
|
179 if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2( |
|
180 Deallocate, jvmti, (unsigned char*)info.name))) |
|
181 return NSK_FALSE; |
|
182 } |
|
183 } |
|
184 |
|
185 /* deallocate threads list */ |
|
186 if (!NSK_JVMTI_VERIFY( |
|
187 NSK_CPP_STUB2(Deallocate, jvmti, (unsigned char*)threads))) |
|
188 return NSK_FALSE; |
|
189 |
|
190 if (thread == NULL) { |
|
191 NSK_COMPLAIN0("Debuggee thread not found"); |
|
192 return NSK_FALSE; |
|
193 } |
|
194 |
|
195 /* make thread accessable for a long time */ |
|
196 if (!NSK_JNI_VERIFY(jni, (thread = |
|
197 NSK_CPP_STUB2(NewGlobalRef, jni, thread)) != NULL)) |
|
198 return NSK_FALSE; |
|
199 |
|
200 /* get tested thread class */ |
|
201 if (!NSK_JNI_VERIFY(jni, (klass = |
|
202 NSK_CPP_STUB2(GetObjectClass, jni, thread)) != NULL)) |
|
203 return NSK_FALSE; |
|
204 |
|
205 /* get tested thread field 'M' */ |
|
206 if (!NSK_JNI_VERIFY(jni, (field = |
|
207 NSK_CPP_STUB4(GetFieldID, jni, klass, "M", FIELD_SIG)) != NULL)) |
|
208 return NSK_FALSE; |
|
209 |
|
210 if (!NSK_JNI_VERIFY(jni, (object_M = |
|
211 NSK_CPP_STUB3(GetObjectField, jni, thread, field)) != NULL)) |
|
212 return NSK_FALSE; |
|
213 |
|
214 /* make object accessable for a long time */ |
|
215 if (!NSK_JNI_VERIFY(jni, (object_M = |
|
216 NSK_CPP_STUB2(NewGlobalRef, jni, object_M)) != NULL)) |
|
217 return NSK_FALSE; |
|
218 |
|
219 /* enable MonitorWait event */ |
|
220 if (!NSK_JVMTI_VERIFY( |
|
221 NSK_CPP_STUB4(SetEventNotificationMode, jvmti, JVMTI_ENABLE, |
|
222 JVMTI_EVENT_MONITOR_WAIT, NULL))) |
|
223 return NSK_FALSE; |
|
224 |
|
225 /* enable MonitorWaited event */ |
|
226 if (!NSK_JVMTI_VERIFY( |
|
227 NSK_CPP_STUB4(SetEventNotificationMode, jvmti, JVMTI_ENABLE, |
|
228 JVMTI_EVENT_MONITOR_WAITED, NULL))) |
|
229 return NSK_FALSE; |
|
230 |
|
231 return NSK_TRUE; |
|
232 } |
|
233 |
|
234 static int clean(jvmtiEnv* jvmti, JNIEnv* jni) { |
|
235 |
|
236 /* disable MonitorWait event */ |
|
237 if (!NSK_JVMTI_VERIFY( |
|
238 NSK_CPP_STUB4(SetEventNotificationMode, jvmti, JVMTI_DISABLE, |
|
239 JVMTI_EVENT_MONITOR_WAIT, NULL))) |
|
240 nsk_jvmti_setFailStatus(); |
|
241 |
|
242 /* disable MonitorWaited event */ |
|
243 if (!NSK_JVMTI_VERIFY( |
|
244 NSK_CPP_STUB4(SetEventNotificationMode, jvmti, JVMTI_DISABLE, |
|
245 JVMTI_EVENT_MONITOR_WAITED, NULL))) |
|
246 nsk_jvmti_setFailStatus(); |
|
247 |
|
248 return NSK_TRUE; |
|
249 } |
|
250 |
|
251 /* ========================================================================== */ |
|
252 |
|
253 /* agent algorithm */ |
|
254 static void JNICALL |
|
255 agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { |
|
256 char buffer[32]; |
|
257 |
|
258 /* wait for initial sync */ |
|
259 if (!nsk_jvmti_waitForSync(timeout)) |
|
260 return; |
|
261 |
|
262 if (!prepare(jvmti, jni)) { |
|
263 nsk_jvmti_setFailStatus(); |
|
264 return; |
|
265 } |
|
266 |
|
267 /* resume debugee to catch MonitorContendedEntered events */ |
|
268 if (!(NSK_VERIFY(nsk_jvmti_resumeSync()) && |
|
269 NSK_VERIFY(nsk_jvmti_waitForSync(timeout)))) |
|
270 return; |
|
271 |
|
272 NSK_DISPLAY1("Number of MonitorWait events: %d\n", waitEventsCount); |
|
273 if (!(NSK_VERIFY(waitEventsCount == 1))) { |
|
274 nsk_jvmti_setFailStatus(); |
|
275 } |
|
276 |
|
277 NSK_DISPLAY1("Number of MonitorWaited events: %d\n", waitedEventsCount); |
|
278 if (!(NSK_VERIFY(waitedEventsCount == 1))) { |
|
279 nsk_jvmti_setFailStatus(); |
|
280 } |
|
281 |
|
282 NSK_DISPLAY1("Time frame between the events: %s ns\n", |
|
283 jlong_to_string(waitedTime - waitTime, buffer)); |
|
284 if (!(NSK_VERIFY((waitedTime - waitTime) >= (EXPECTED_TIMEOUT * 1000000) - EXPECTED_TIMEOUT_ACCURACY_NS))) { |
|
285 #if (defined(WIN32) || defined(_WIN32)) |
|
286 /* Do not fail on Windows as spurious wakeups are expected. The JDK-6313903 was closed as "Won't Fix". */ |
|
287 #else |
|
288 nsk_jvmti_setFailStatus(); |
|
289 #endif |
|
290 printf("waitedTime: %" LL "d, waitTime: %" LL "d, waitedTime - waitTime: %" LL "d\n", |
|
291 waitedTime, waitTime, waitedTime - waitTime); |
|
292 } |
|
293 |
|
294 NSK_DISPLAY1("Thread CPU time between the events: %s ns\n", |
|
295 jlong_to_string(waitedThreadCpuTime - waitThreadCpuTime, buffer)); |
|
296 if (!(NSK_VERIFY((waitedThreadCpuTime - waitThreadCpuTime) |
|
297 < (EXPECTED_ACCURACY * 1000000)))) { |
|
298 nsk_jvmti_setFailStatus(); |
|
299 printf("waitedThreadCpuTime: %" LL "d, waitThreadCpuTime: %" LL "d, waitedThreadCpuTime - waitThreadCpuTime: %" LL "d\n", |
|
300 waitedThreadCpuTime, waitThreadCpuTime, waitedThreadCpuTime - waitThreadCpuTime); |
|
301 } |
|
302 |
|
303 if (!clean(jvmti, jni)) { |
|
304 nsk_jvmti_setFailStatus(); |
|
305 return; |
|
306 } |
|
307 |
|
308 /* resume debugee after last sync */ |
|
309 if (!nsk_jvmti_resumeSync()) |
|
310 return; |
|
311 } |
|
312 |
|
313 /* ========================================================================== */ |
|
314 |
|
315 /* agent library initialization */ |
|
316 #ifdef STATIC_BUILD |
|
317 JNIEXPORT jint JNICALL Agent_OnLoad_tc05t001(JavaVM *jvm, char *options, void *reserved) { |
|
318 return Agent_Initialize(jvm, options, reserved); |
|
319 } |
|
320 JNIEXPORT jint JNICALL Agent_OnAttach_tc05t001(JavaVM *jvm, char *options, void *reserved) { |
|
321 return Agent_Initialize(jvm, options, reserved); |
|
322 } |
|
323 JNIEXPORT jint JNI_OnLoad_tc05t001(JavaVM *jvm, char *options, void *reserved) { |
|
324 return JNI_VERSION_1_8; |
|
325 } |
|
326 #endif |
|
327 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { |
|
328 jvmtiEnv* jvmti = NULL; |
|
329 jvmtiCapabilities caps; |
|
330 jvmtiEventCallbacks callbacks; |
|
331 |
|
332 /* init framework and parse options */ |
|
333 if (!NSK_VERIFY(nsk_jvmti_parseOptions(options))) |
|
334 return JNI_ERR; |
|
335 |
|
336 timeout = nsk_jvmti_getWaitTime() * 60000; |
|
337 NSK_DISPLAY1("Timeout: %d msc\n", (int)timeout); |
|
338 |
|
339 /* create JVMTI environment */ |
|
340 if (!NSK_VERIFY((jvmti = |
|
341 nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL)) |
|
342 return JNI_ERR; |
|
343 |
|
344 /* add capabilities */ |
|
345 memset(&caps, 0, sizeof(caps)); |
|
346 caps.can_generate_monitor_events = 1; |
|
347 caps.can_get_thread_cpu_time = 1; |
|
348 if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(AddCapabilities, jvmti, &caps))) |
|
349 return JNI_ERR; |
|
350 |
|
351 memset(&callbacks, 0, sizeof(callbacks)); |
|
352 callbacks.MonitorWait = &MonitorWait; |
|
353 callbacks.MonitorWaited = &MonitorWaited; |
|
354 if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(SetEventCallbacks, jvmti, |
|
355 &callbacks, sizeof(callbacks)))) |
|
356 return JNI_ERR; |
|
357 |
|
358 /* register agent proc and arg */ |
|
359 if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL))) |
|
360 return JNI_ERR; |
|
361 |
|
362 return JNI_OK; |
|
363 } |
|
364 |
|
365 /* ========================================================================== */ |
|
366 |
|
367 #ifdef __cplusplus |
|
368 } |
|
369 #endif |