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