Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/javax/management/remote/mandatory/notif/NotificationBufferDeadlockTest.java
38867 views
1
/*
2
* Copyright (c) 2005, 2015, 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
/*
25
* @test
26
* @bug 6239400
27
* @summary Tests NotificationBuffer doesn't hold locks when adding listeners,
28
* if test times out then deadlock is suspected.
29
* @author Eamonn McManus
30
* @run clean NotificationBufferDeadlockTest
31
* @run build NotificationBufferDeadlockTest
32
* @run main NotificationBufferDeadlockTest
33
*/
34
35
import java.lang.reflect.InvocationHandler;
36
import java.lang.reflect.Method;
37
import java.lang.reflect.Proxy;
38
import java.net.MalformedURLException;
39
import java.util.List;
40
import java.util.Set;
41
import java.util.Vector;
42
import java.util.concurrent.CountDownLatch;
43
import javax.management.*;
44
import javax.management.remote.*;
45
46
/*
47
* Regression test for a rare but not unheard-of deadlock condition in
48
* the notification buffer support for connector servers.
49
* See bug 6239400 for the description of the bug and the example that
50
* showed it up.
51
*
52
* Here we test that, when the connector server adds its listener to an
53
* MBean, it is not holding a lock that would prevent another thread from
54
* emitting a notification (from that MBean or another one). This is
55
* important, because we don't know how user MBeans might implement
56
* NotificationBroadcaster.addNotificationListener, and in particular we
57
* can't be sure that the method is well-behaved and can never do a
58
* blocking operation, such as attempting to acquire a lock that is also
59
* acquired when notifications are emitted.
60
*
61
* The test creates a special MBean whose addNotificationListener method
62
* does the standard addNotificationListener logic inherited
63
* from NotificationBroadcasterSupport, then
64
* creates another thread that emits a notification from the same MBean.
65
* The addNotificationListener method waits for this thread to complete.
66
* If the notification buffer logic is incorrect, then emitting the
67
* notification will attempt to acquire the lock on the buffer, but that
68
* lock is being held by the thread that called addNotificationListener,
69
* so there will be deadlock.
70
*
71
* We use this DeadlockMBean several times. First, we create one and then
72
* add a remote listener to it. The first time you add a remote listener
73
* through a connector server, the connector server adds its own listener
74
* to all NotificationBroadcaster MBeans. If it holds a lock while doing
75
* this, we will see deadlock.
76
*
77
* Then we create a second DeadlockMBean. When a new MBean is created that
78
* is a NotificationBroadcaster, the connector server adds its listener to
79
* that MBean too. Again if it holds a lock while doing this, we will see
80
* deadlock.
81
*
82
* Finally, we do some magic with MBeanServerForwarders so that while
83
* queryNames is running (to find MBeans to which listeners must be added)
84
* we will create new MBeans. This tests that this tricky situation is
85
* handled correctly. It also tests the queryNames that is run when the
86
* notification buffer is being destroyed (to remove the listeners).
87
*
88
* We cause all of our test MBeans to emit exactly one notification and
89
* check that we have received exactly one notification from each MBean.
90
* If the logic for adding the notification buffer's listener is incorrect
91
* we could remove zero or two notifications from an MBean.
92
*/
93
public class NotificationBufferDeadlockTest {
94
public static void main(String[] args) throws Exception {
95
System.out.println("Check no deadlock if notif sent while initial " +
96
"remote listeners being added");
97
final String[] protos = {"rmi", "iiop", "jmxmp"};
98
for (String p : protos) {
99
try {
100
test(p);
101
} catch (Exception e) {
102
System.out.println("TEST FAILED: GOT EXCEPTION:");
103
e.printStackTrace(System.out);
104
failure = e.toString();
105
}
106
}
107
if (failure == null)
108
return;
109
else
110
throw new Exception("TEST FAILED: " + failure);
111
}
112
113
private static void test(String proto) throws Exception {
114
System.out.println("Testing protocol " + proto);
115
MBeanServer mbs = MBeanServerFactory.newMBeanServer();
116
ObjectName testName = newName();
117
DeadlockTest test = new DeadlockTest();
118
mbs.registerMBean(test, testName);
119
JMXServiceURL url = new JMXServiceURL("service:jmx:" + proto + ":///");
120
JMXConnectorServer cs;
121
try {
122
cs =
123
JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
124
} catch (MalformedURLException e) {
125
System.out.println("...protocol not supported, ignoring");
126
return;
127
}
128
129
MBeanServerForwarder createDuringQueryForwarder = (MBeanServerForwarder)
130
Proxy.newProxyInstance(new Object() {}.getClass().getClassLoader(),
131
new Class[] {MBeanServerForwarder.class},
132
new CreateDuringQueryInvocationHandler());
133
cs.setMBeanServerForwarder(createDuringQueryForwarder);
134
cs.start();
135
JMXServiceURL addr = cs.getAddress();
136
JMXConnector cc = JMXConnectorFactory.connect(addr);
137
MBeanServerConnection mbsc = cc.getMBeanServerConnection();
138
try {
139
String fail = test(mbsc, testName);
140
if (fail != null)
141
System.out.println("FAILED: " + fail);
142
failure = fail;
143
} finally {
144
cc.close();
145
cs.stop();
146
}
147
}
148
149
private static String test(MBeanServerConnection mbsc,
150
ObjectName testName) throws Exception {
151
152
NotificationListener dummyListener = new NotificationListener() {
153
public void handleNotification(Notification n, Object h) {
154
}
155
};
156
thisFailure = null;
157
mbsc.addNotificationListener(testName, dummyListener, null, null);
158
if (thisFailure != null)
159
return thisFailure;
160
ObjectName newName = newName();
161
mbsc.createMBean(DeadlockTest.class.getName(), newName);
162
if (thisFailure != null)
163
return thisFailure;
164
Set<ObjectName> names =
165
mbsc.queryNames(new ObjectName("d:type=DeadlockTest,*"), null);
166
System.out.printf("...found %d test MBeans\n", names.size());
167
168
sources.clear();
169
countListener = new MyListener(names.size());
170
171
for (ObjectName name : names)
172
mbsc.addNotificationListener(name, countListener, null, null);
173
if (thisFailure != null)
174
return thisFailure;
175
for (ObjectName name : names)
176
mbsc.invoke(name, "send", null, null);
177
178
countListener.waiting();
179
180
if (!sources.containsAll(names))
181
return "missing names: " + sources;
182
return thisFailure;
183
}
184
185
public static interface DeadlockTestMBean {
186
public void send();
187
}
188
189
public static class DeadlockTest extends NotificationBroadcasterSupport
190
implements DeadlockTestMBean {
191
@Override
192
public void addNotificationListener(NotificationListener listener,
193
NotificationFilter filter,
194
Object handback) {
195
super.addNotificationListener(listener, filter, handback);
196
Thread t = new Thread() {
197
@Override
198
public void run() {
199
Notification n =
200
new Notification("type", DeadlockTest.this, 0L);
201
DeadlockTest.this.sendNotification(n);
202
}
203
};
204
t.start();
205
System.out.println("DeadlockTest-addNotificationListener waiting for the sending thread to die...");
206
try {
207
t.join(); //if times out here then deadlock is suspected
208
System.out.println("DeadlockTest-addNotificationListener OK.");
209
} catch (Exception e) {
210
thisFailure = "Join exception: " + e;
211
}
212
}
213
214
public void send() {
215
sendNotification(new Notification(TESTING_TYPE, DeadlockTest.this, 1L));
216
}
217
}
218
219
private static class CreateDuringQueryInvocationHandler
220
implements InvocationHandler {
221
public Object invoke(Object proxy, Method m, Object[] args)
222
throws Throwable {
223
if (m.getName().equals("setMBeanServer")) {
224
mbs = (MBeanServer) args[0];
225
return null;
226
}
227
createMBeanIfQuery(m);
228
Object ret = m.invoke(mbs, args);
229
createMBeanIfQuery(m);
230
return ret;
231
}
232
233
private void createMBeanIfQuery(Method m) throws InterruptedException {
234
if (m.getName().equals("queryNames")) {
235
Thread t = new Thread() {
236
public void run() {
237
try {
238
mbs.createMBean(DeadlockTest.class.getName(),
239
newName());
240
} catch (Exception e) {
241
e.printStackTrace();
242
thisFailure = e.toString();
243
}
244
}
245
};
246
t.start();
247
System.out.println("CreateDuringQueryInvocationHandler-createMBeanIfQuery waiting for the creating thread to die...");
248
t.join(); // if times out here then deadlock is suspected
249
System.out.println("CreateDuringQueryInvocationHandler-createMBeanIfQuery OK");
250
}
251
}
252
253
private MBeanServer mbs;
254
}
255
256
private static synchronized ObjectName newName() {
257
try {
258
return new ObjectName("d:type=DeadlockTest,instance=" +
259
++nextNameIndex);
260
} catch (MalformedObjectNameException e) {
261
throw new IllegalArgumentException("bad ObjectName", e);
262
}
263
}
264
265
private static class MyListener implements NotificationListener {
266
public MyListener(int waitNB) {
267
count = new CountDownLatch(waitNB);
268
}
269
270
public void handleNotification(Notification n, Object h) {
271
System.out.println("MyListener got: " + n.getSource() + " " + n.getType());
272
273
if (TESTING_TYPE.equals(n.getType())) {
274
sources.add((ObjectName) n.getSource());
275
count.countDown();
276
}
277
}
278
279
public void waiting() throws InterruptedException {
280
System.out.println("MyListener-waiting ...");
281
count.await(); // if times out here then deadlock is suspected
282
System.out.println("MyListener-waiting done!");
283
}
284
285
private final CountDownLatch count;
286
}
287
288
static String thisFailure;
289
static String failure;
290
static int nextNameIndex;
291
292
private static MyListener countListener;
293
private static final List<ObjectName> sources = new Vector();
294
295
private static final String TESTING_TYPE = "testing_type";
296
}
297
298