|
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 /* scaffold objects */ |
|
37 static jlong timeout = 0; |
|
38 |
|
39 /* test objects */ |
|
40 static jthread thread = NULL; |
|
41 static jobject object_M = NULL; |
|
42 /* line numbers of "synchronized (M)" clauses in java part of the test */ |
|
43 static jint lines[] = { 127, 132, 137 }; |
|
44 static volatile int enterEventsCount = 0; |
|
45 static volatile int enteredEventsCount = 0; |
|
46 |
|
47 /* ========================================================================== */ |
|
48 |
|
49 static jint findLineNumber(jvmtiEnv *jvmti, jthread thread) { |
|
50 jmethodID method = NULL; |
|
51 jlocation location; |
|
52 jvmtiLineNumberEntry* table = NULL; |
|
53 jint count = 0; |
|
54 jint line = 0; |
|
55 int i; |
|
56 |
|
57 if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB5( |
|
58 GetFrameLocation, jvmti, thread, 0, &method, &location))) |
|
59 return 0; |
|
60 |
|
61 if (!NSK_VERIFY(method != NULL)) |
|
62 return 0; |
|
63 |
|
64 if (!NSK_VERIFY(location != -1)) |
|
65 return 0; |
|
66 |
|
67 if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4( |
|
68 GetLineNumberTable, jvmti, method, &count, &table))) |
|
69 return 0; |
|
70 |
|
71 if (!NSK_VERIFY(table != NULL)) |
|
72 return 0; |
|
73 |
|
74 if (!NSK_VERIFY(count > 0)) |
|
75 return 0; |
|
76 |
|
77 for (i = 0; i < count; i++) { |
|
78 if (location < table[i].start_location) { |
|
79 break; |
|
80 } |
|
81 } |
|
82 |
|
83 line = table[i-1].line_number; |
|
84 |
|
85 if (table != NULL) { |
|
86 if (!NSK_JVMTI_VERIFY( |
|
87 NSK_CPP_STUB2(Deallocate, jvmti, (unsigned char*)table))) |
|
88 return 0; |
|
89 } |
|
90 |
|
91 return line; |
|
92 } |
|
93 |
|
94 /* ========================================================================== */ |
|
95 |
|
96 void JNICALL |
|
97 MonitorContendedEnter(jvmtiEnv *jvmti, JNIEnv* jni, jthread thr, jobject obj) { |
|
98 jint line = 0; |
|
99 |
|
100 if (!NSK_VERIFY(thr != NULL)) { |
|
101 nsk_jvmti_setFailStatus(); |
|
102 NSK_COMPLAIN1("MonitorContendedEnter event: thread=%p\n", thr); |
|
103 return; |
|
104 } |
|
105 |
|
106 if (!NSK_VERIFY(obj != NULL)) { |
|
107 nsk_jvmti_setFailStatus(); |
|
108 NSK_COMPLAIN1("MonitorContendedEnter event: object=%p\n", obj); |
|
109 return; |
|
110 } |
|
111 |
|
112 /* check if event is for tested thread and object */ |
|
113 if (NSK_CPP_STUB3(IsSameObject, jni, thread, thr) && |
|
114 NSK_CPP_STUB3(IsSameObject, jni, object_M, obj)) { |
|
115 |
|
116 if (!(line = findLineNumber(jvmti, thread))) { |
|
117 nsk_jvmti_setFailStatus(); |
|
118 NSK_COMPLAIN2("MonitorContendedEnter event: thread=%p, object=%p\n", |
|
119 thr, obj); |
|
120 return; |
|
121 } |
|
122 |
|
123 NSK_DISPLAY3("MonitorContendedEnter event: thread=%p, object=%p, line=%d\n", |
|
124 thr, obj, line); |
|
125 |
|
126 /* workaround of 4527285 bug: in -Xint mode GetFrameLocation |
|
127 returns the location after the monitor enter. |
|
128 */ |
|
129 if (!NSK_VERIFY(line == lines[enterEventsCount] || |
|
130 line == (lines[enterEventsCount] + 1))) { |
|
131 nsk_jvmti_setFailStatus(); |
|
132 NSK_COMPLAIN3("MonitorContendedEnter event: thread=%p, object=%p, line=%d\n", |
|
133 thr, obj, line); |
|
134 } |
|
135 |
|
136 enterEventsCount++; |
|
137 } |
|
138 } |
|
139 |
|
140 void JNICALL |
|
141 MonitorContendedEntered(jvmtiEnv *jvmti, JNIEnv* jni, jthread thr, jobject obj) { |
|
142 jint line = 0; |
|
143 |
|
144 if (!NSK_VERIFY(thr != NULL)) { |
|
145 nsk_jvmti_setFailStatus(); |
|
146 NSK_COMPLAIN1("MonitorContendedEntered event: thread=%p\n", thr); |
|
147 return; |
|
148 } |
|
149 |
|
150 if (!NSK_VERIFY(obj != NULL)) { |
|
151 nsk_jvmti_setFailStatus(); |
|
152 NSK_COMPLAIN1("MonitorContendedEntered event: object=%p\n", obj); |
|
153 return; |
|
154 } |
|
155 |
|
156 /* check if event is for tested thread and object */ |
|
157 if (NSK_CPP_STUB3(IsSameObject, jni, thread, thr) && |
|
158 NSK_CPP_STUB3(IsSameObject, jni, object_M, obj)) { |
|
159 |
|
160 if (!(line = findLineNumber(jvmti, thread))) { |
|
161 nsk_jvmti_setFailStatus(); |
|
162 NSK_COMPLAIN2("MonitorContendedEntered event: thread=%p, object=%p\n", |
|
163 thr, obj); |
|
164 return; |
|
165 } |
|
166 |
|
167 NSK_DISPLAY3("MonitorContendedEntered event: thread=%p, object=%p, line=%d\n", |
|
168 thr, obj, line); |
|
169 |
|
170 /* workaround of 4527285 bug: in -Xint mode GetFrameLocation |
|
171 returns the location after the monitor enter. |
|
172 */ |
|
173 if (!NSK_VERIFY(line == lines[enteredEventsCount] || |
|
174 line == (lines[enteredEventsCount] + 1))) { |
|
175 nsk_jvmti_setFailStatus(); |
|
176 NSK_COMPLAIN3("MonitorContendedEntered event: thread=%p, object=%p, line=%d\n", |
|
177 thr, obj, line); |
|
178 } |
|
179 |
|
180 enteredEventsCount++; |
|
181 } |
|
182 } |
|
183 |
|
184 /* ========================================================================== */ |
|
185 |
|
186 static int prepare(jvmtiEnv* jvmti, JNIEnv* jni) { |
|
187 const char* THREAD_NAME = "Debuggee Thread"; |
|
188 const char* FIELD_SIG = "Ljava/lang/Object;"; |
|
189 jvmtiThreadInfo info; |
|
190 jthread *threads = NULL; |
|
191 jint threads_count = 0; |
|
192 jfieldID field = NULL; |
|
193 jclass klass = NULL; |
|
194 int i; |
|
195 |
|
196 NSK_DISPLAY0("Prepare: find tested thread\n"); |
|
197 |
|
198 /* get all live threads */ |
|
199 if (!NSK_JVMTI_VERIFY( |
|
200 NSK_CPP_STUB3(GetAllThreads, jvmti, &threads_count, &threads))) |
|
201 return NSK_FALSE; |
|
202 |
|
203 if (!NSK_VERIFY(threads_count > 0 && threads != NULL)) |
|
204 return NSK_FALSE; |
|
205 |
|
206 /* find tested thread */ |
|
207 for (i = 0; i < threads_count; i++) { |
|
208 if (!NSK_VERIFY(threads[i] != NULL)) |
|
209 return NSK_FALSE; |
|
210 |
|
211 /* get thread information */ |
|
212 if (!NSK_JVMTI_VERIFY( |
|
213 NSK_CPP_STUB3(GetThreadInfo, jvmti, threads[i], &info))) |
|
214 return NSK_FALSE; |
|
215 |
|
216 NSK_DISPLAY3(" thread #%d (%s): %p\n", i, info.name, threads[i]); |
|
217 |
|
218 /* find by name */ |
|
219 if (info.name != NULL && (strcmp(info.name, THREAD_NAME) == 0)) { |
|
220 thread = threads[i]; |
|
221 } |
|
222 |
|
223 if (info.name != NULL) { |
|
224 if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2( |
|
225 Deallocate, jvmti, (unsigned char*)info.name))) |
|
226 return NSK_FALSE; |
|
227 } |
|
228 } |
|
229 |
|
230 /* deallocate threads list */ |
|
231 if (!NSK_JVMTI_VERIFY( |
|
232 NSK_CPP_STUB2(Deallocate, jvmti, (unsigned char*)threads))) |
|
233 return NSK_FALSE; |
|
234 |
|
235 if (thread == NULL) { |
|
236 NSK_COMPLAIN0("Debuggee thread not found"); |
|
237 return NSK_FALSE; |
|
238 } |
|
239 |
|
240 /* make thread accessable for a long time */ |
|
241 if (!NSK_JNI_VERIFY(jni, (thread = |
|
242 NSK_CPP_STUB2(NewGlobalRef, jni, thread)) != NULL)) |
|
243 return NSK_FALSE; |
|
244 |
|
245 /* get tested thread class */ |
|
246 if (!NSK_JNI_VERIFY(jni, (klass = |
|
247 NSK_CPP_STUB2(GetObjectClass, jni, thread)) != NULL)) |
|
248 return NSK_FALSE; |
|
249 |
|
250 /* get tested thread field 'M' */ |
|
251 if (!NSK_JNI_VERIFY(jni, (field = |
|
252 NSK_CPP_STUB4(GetFieldID, jni, klass, "M", FIELD_SIG)) != NULL)) |
|
253 return NSK_FALSE; |
|
254 |
|
255 if (!NSK_JNI_VERIFY(jni, (object_M = |
|
256 NSK_CPP_STUB3(GetObjectField, jni, thread, field)) != NULL)) |
|
257 return NSK_FALSE; |
|
258 |
|
259 /* make object accessable for a long time */ |
|
260 if (!NSK_JNI_VERIFY(jni, (object_M = |
|
261 NSK_CPP_STUB2(NewGlobalRef, jni, object_M)) != NULL)) |
|
262 return NSK_FALSE; |
|
263 |
|
264 /* enable MonitorContendedEntered event */ |
|
265 if (!NSK_JVMTI_VERIFY( |
|
266 NSK_CPP_STUB4(SetEventNotificationMode, jvmti, JVMTI_ENABLE, |
|
267 JVMTI_EVENT_MONITOR_CONTENDED_ENTER, NULL))) |
|
268 return NSK_FALSE; |
|
269 |
|
270 /* enable MonitorContendedEntered event */ |
|
271 if (!NSK_JVMTI_VERIFY( |
|
272 NSK_CPP_STUB4(SetEventNotificationMode, jvmti, JVMTI_ENABLE, |
|
273 JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, NULL))) |
|
274 return NSK_FALSE; |
|
275 |
|
276 return NSK_TRUE; |
|
277 } |
|
278 |
|
279 static int clean(jvmtiEnv* jvmti, JNIEnv* jni) { |
|
280 |
|
281 /* disable MonitorContendedEntered event */ |
|
282 if (!NSK_JVMTI_VERIFY( |
|
283 NSK_CPP_STUB4(SetEventNotificationMode, jvmti, JVMTI_DISABLE, |
|
284 JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, NULL))) |
|
285 nsk_jvmti_setFailStatus(); |
|
286 |
|
287 return NSK_TRUE; |
|
288 } |
|
289 |
|
290 /* ========================================================================== */ |
|
291 |
|
292 /* agent algorithm */ |
|
293 static void JNICALL |
|
294 agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { |
|
295 |
|
296 /* wait for initial sync */ |
|
297 if (!nsk_jvmti_waitForSync(timeout)) |
|
298 return; |
|
299 |
|
300 if (!prepare(jvmti, jni)) { |
|
301 nsk_jvmti_setFailStatus(); |
|
302 return; |
|
303 } |
|
304 |
|
305 /* resume debugee to catch MonitorContendedEntered events */ |
|
306 if (!(NSK_VERIFY(nsk_jvmti_resumeSync()) && |
|
307 NSK_VERIFY(nsk_jvmti_waitForSync(timeout)))) |
|
308 return; |
|
309 |
|
310 NSK_DISPLAY1("Number of MonitorContendedEnter events: %d\n", |
|
311 enterEventsCount); |
|
312 |
|
313 if (!(NSK_VERIFY(enterEventsCount == 3))) { |
|
314 nsk_jvmti_setFailStatus(); |
|
315 } |
|
316 |
|
317 NSK_DISPLAY1("Number of MonitorContendedEntered events: %d\n", |
|
318 enteredEventsCount); |
|
319 |
|
320 if (!(NSK_VERIFY(enteredEventsCount == 3))) { |
|
321 nsk_jvmti_setFailStatus(); |
|
322 } |
|
323 |
|
324 if (!clean(jvmti, jni)) { |
|
325 nsk_jvmti_setFailStatus(); |
|
326 return; |
|
327 } |
|
328 |
|
329 /* resume debugee after last sync */ |
|
330 if (!nsk_jvmti_resumeSync()) |
|
331 return; |
|
332 } |
|
333 |
|
334 /* ========================================================================== */ |
|
335 |
|
336 /* agent library initialization */ |
|
337 #ifdef STATIC_BUILD |
|
338 JNIEXPORT jint JNICALL Agent_OnLoad_tc02t001(JavaVM *jvm, char *options, void *reserved) { |
|
339 return Agent_Initialize(jvm, options, reserved); |
|
340 } |
|
341 JNIEXPORT jint JNICALL Agent_OnAttach_tc02t001(JavaVM *jvm, char *options, void *reserved) { |
|
342 return Agent_Initialize(jvm, options, reserved); |
|
343 } |
|
344 JNIEXPORT jint JNI_OnLoad_tc02t001(JavaVM *jvm, char *options, void *reserved) { |
|
345 return JNI_VERSION_1_8; |
|
346 } |
|
347 #endif |
|
348 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { |
|
349 jvmtiEnv* jvmti = NULL; |
|
350 jvmtiCapabilities caps; |
|
351 jvmtiEventCallbacks callbacks; |
|
352 |
|
353 /* init framework and parse options */ |
|
354 if (!NSK_VERIFY(nsk_jvmti_parseOptions(options))) |
|
355 return JNI_ERR; |
|
356 |
|
357 timeout = nsk_jvmti_getWaitTime() * 60000; |
|
358 NSK_DISPLAY1("Timeout: %d msc\n", (int)timeout); |
|
359 |
|
360 /* create JVMTI environment */ |
|
361 if (!NSK_VERIFY((jvmti = |
|
362 nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL)) |
|
363 return JNI_ERR; |
|
364 |
|
365 /* add capabilities */ |
|
366 memset(&caps, 0, sizeof(caps)); |
|
367 caps.can_generate_monitor_events = 1; |
|
368 caps.can_get_line_numbers = 1; |
|
369 if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(AddCapabilities, jvmti, &caps))) |
|
370 return JNI_ERR; |
|
371 |
|
372 memset(&callbacks, 0, sizeof(callbacks)); |
|
373 callbacks.MonitorContendedEnter = &MonitorContendedEnter; |
|
374 callbacks.MonitorContendedEntered = &MonitorContendedEntered; |
|
375 if (!NSK_JVMTI_VERIFY( |
|
376 NSK_CPP_STUB3(SetEventCallbacks, jvmti, |
|
377 &callbacks, sizeof(callbacks)))) |
|
378 return JNI_ERR; |
|
379 |
|
380 /* register agent proc and arg */ |
|
381 if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL))) |
|
382 return JNI_ERR; |
|
383 |
|
384 return JNI_OK; |
|
385 } |
|
386 |
|
387 /* ========================================================================== */ |
|
388 |
|
389 #ifdef __cplusplus |
|
390 } |
|
391 #endif |