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