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 extern "C" {
31
32 typedef struct {
33 jthread thread;
34 char* name;
35 int dfn;
36 } threadDesc;
37
38 /* ========================================================================== */
39
40 /* scaffold objects */
41 static jlong timeout = 0;
42
43 /* test objects */
44 static threadDesc *threadList = NULL;
45 static jint threads_count = 0;
46 static int numberOfDeadlocks = 0;
47
48 /* ========================================================================== */
49
printDeadlock(jvmtiEnv * jvmti,JNIEnv * jni,int dThread)50 static int printDeadlock(jvmtiEnv* jvmti, JNIEnv* jni, int dThread) {
51 jobject monitor = NULL;
52 jclass klass = NULL;
53 jvmtiMonitorUsage usageInfo;
54 int pThread, cThread;
55 char* name;
56
57 NSK_DISPLAY1("Found deadlock #%d:\n", numberOfDeadlocks);
58 for (pThread = dThread;;pThread = cThread) {
59 NSK_DISPLAY1(" \"%s\":\n", threadList[pThread].name);
60 if (!NSK_JVMTI_VERIFY(
61 jvmti->GetCurrentContendedMonitor(threadList[pThread].thread, &monitor)))
62 return NSK_FALSE;
63 if (monitor != NULL) {
64 if (!NSK_JNI_VERIFY(jni, (klass = jni->GetObjectClass(monitor)) != NULL))
65 return NSK_FALSE;
66 if (!NSK_JVMTI_VERIFY(jvmti->GetClassSignature(klass, &name, NULL)))
67 return NSK_FALSE;
68 NSK_DISPLAY2(" waiting to lock %p (%s),\n", monitor, name);
69 jvmti->Deallocate((unsigned char*)name);
70 } else {
71 NSK_DISPLAY0(" (JVMTI raw monitor),\n");
72 }
73 if (!NSK_JVMTI_VERIFY(jvmti->GetObjectMonitorUsage(monitor, &usageInfo)))
74 return NSK_FALSE;
75 if (usageInfo.owner == NULL)
76 break;
77 for (cThread = 0; cThread < threads_count; cThread++) {
78 if (jni->IsSameObject(threadList[cThread].thread, usageInfo.owner))
79 break;
80 }
81 if (usageInfo.waiters != NULL) {
82 jvmti->Deallocate((unsigned char*)usageInfo.waiters);
83 }
84 if (usageInfo.notify_waiters != NULL) {
85 jvmti->Deallocate((unsigned char*)usageInfo.notify_waiters);
86 }
87 if (!NSK_VERIFY(cThread != threads_count))
88 return NSK_FALSE;
89 NSK_DISPLAY1(" which is held by \"%s\"\n",
90 threadList[cThread].name);
91 if (cThread == dThread)
92 break;
93 }
94
95 return NSK_TRUE;
96 }
97
findDeadlockThreads(jvmtiEnv * jvmti,JNIEnv * jni)98 static int findDeadlockThreads(jvmtiEnv* jvmti, JNIEnv* jni) {
99 jvmtiThreadInfo info;
100 jthread *threads = NULL;
101 jobject monitor = NULL;
102 jvmtiMonitorUsage usageInfo;
103 int tDfn = 0, gDfn = 0;
104 int pThread, cThread;
105 int i;
106
107 NSK_DISPLAY0("Create threadList\n");
108
109 /* get all live threads */
110 if (!NSK_JVMTI_VERIFY(jvmti->GetAllThreads(&threads_count, &threads)))
111 return NSK_FALSE;
112
113 if (!NSK_VERIFY(threads_count > 0 && threads != NULL))
114 return NSK_FALSE;
115
116 if (!NSK_JVMTI_VERIFY(
117 jvmti->Allocate(threads_count*sizeof(threadDesc), (unsigned char**)&threadList)))
118 return NSK_FALSE;
119
120 for (i = 0; i < threads_count; i++) {
121 if (!NSK_VERIFY(threads[i] != NULL))
122 return NSK_FALSE;
123
124 /* get thread information */
125 if (!NSK_JVMTI_VERIFY(jvmti->GetThreadInfo(threads[i], &info)))
126 return NSK_FALSE;
127
128 NSK_DISPLAY3(" thread #%d (%s): %p\n", i, info.name, threads[i]);
129
130 threadList[i].thread = threads[i];
131 threadList[i].dfn = -1;
132 threadList[i].name = info.name;
133 }
134
135 /* deallocate thread list */
136 if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)threads)))
137 return NSK_FALSE;
138
139 for (i = 0; i < threads_count; i++) {
140 if (threadList[i].dfn < 0) {
141 tDfn = gDfn;
142 threadList[i].dfn = gDfn++;
143 for (pThread = i;;pThread = cThread) {
144 if (!NSK_JVMTI_VERIFY(
145 jvmti->GetCurrentContendedMonitor(threadList[pThread].thread, &monitor)))
146 return NSK_FALSE;
147 if (monitor == NULL)
148 break;
149 if (!NSK_JVMTI_VERIFY(jvmti->GetObjectMonitorUsage(monitor, &usageInfo)))
150 return NSK_FALSE;
151 if (usageInfo.owner == NULL)
152 break;
153 for (cThread = 0; cThread < threads_count; cThread++) {
154 if (jni->IsSameObject(threadList[cThread].thread, usageInfo.owner))
155 break;
156 }
157 if (usageInfo.waiters != NULL) {
158 jvmti->Deallocate((unsigned char*)usageInfo.waiters);
159 }
160 if (usageInfo.notify_waiters != NULL) {
161 jvmti->Deallocate((unsigned char*)usageInfo.notify_waiters);
162 }
163 if (!NSK_VERIFY(cThread != threads_count))
164 return NSK_FALSE;
165 if (threadList[cThread].dfn < 0) {
166 threadList[cThread].dfn = gDfn++;
167 } else if (cThread == pThread) {
168 break;
169 } else {
170 numberOfDeadlocks++;
171 if (nsk_getVerboseMode()) {
172 if (!printDeadlock(jvmti, jni, cThread))
173 return NSK_FALSE;
174 }
175 break;
176 }
177 }
178 }
179 }
180
181 /* deallocate thread names */
182 for (i = 0; i < threads_count; i++) {
183 if (threadList[i].name != NULL) {
184 if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)threadList[i].name)))
185 return NSK_FALSE;
186 }
187 }
188
189 return NSK_TRUE;
190 }
191
192 /* ========================================================================== */
193
194 /* agent algorithm */
195 static void JNICALL
agentProc(jvmtiEnv * jvmti,JNIEnv * jni,void * arg)196 agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) {
197
198 /* wait for initial sync */
199 if (!nsk_jvmti_waitForSync(timeout))
200 return;
201
202 if (!findDeadlockThreads(jvmti, jni)) {
203 nsk_jvmti_setFailStatus();
204 return;
205 }
206
207 NSK_DISPLAY1("Total deadlocks found: %d\n", numberOfDeadlocks);
208 if (!NSK_VERIFY(numberOfDeadlocks > 0))
209 nsk_jvmti_setFailStatus();
210
211 /* resume debugee after last sync */
212 if (!nsk_jvmti_resumeSync())
213 return;
214 }
215
216 /* ========================================================================== */
217
218 /* agent library initialization */
219 #ifdef STATIC_BUILD
Agent_OnLoad_tc03t001(JavaVM * jvm,char * options,void * reserved)220 JNIEXPORT jint JNICALL Agent_OnLoad_tc03t001(JavaVM *jvm, char *options, void *reserved) {
221 return Agent_Initialize(jvm, options, reserved);
222 }
Agent_OnAttach_tc03t001(JavaVM * jvm,char * options,void * reserved)223 JNIEXPORT jint JNICALL Agent_OnAttach_tc03t001(JavaVM *jvm, char *options, void *reserved) {
224 return Agent_Initialize(jvm, options, reserved);
225 }
JNI_OnLoad_tc03t001(JavaVM * jvm,char * options,void * reserved)226 JNIEXPORT jint JNI_OnLoad_tc03t001(JavaVM *jvm, char *options, void *reserved) {
227 return JNI_VERSION_1_8;
228 }
229 #endif
Agent_Initialize(JavaVM * jvm,char * options,void * reserved)230 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
231 jvmtiEnv* jvmti = NULL;
232 jvmtiCapabilities caps;
233
234 /* init framework and parse options */
235 if (!NSK_VERIFY(nsk_jvmti_parseOptions(options)))
236 return JNI_ERR;
237
238 timeout = nsk_jvmti_getWaitTime() * 60000;
239 NSK_DISPLAY1("Timeout: %d msc\n", (int)timeout);
240
241 /* create JVMTI environment */
242 if (!NSK_VERIFY((jvmti =
243 nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL))
244 return JNI_ERR;
245
246 /* add capabilities */
247 memset(&caps, 0, sizeof(caps));
248 caps.can_get_current_contended_monitor = 1;
249 caps.can_get_monitor_info = 1;
250 if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&caps)))
251 return JNI_ERR;
252
253 /* register agent proc and arg */
254 if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL)))
255 return JNI_ERR;
256
257 return JNI_OK;
258 }
259
260 /* ========================================================================== */
261
262 }
263