blob: 7ec47f6e3108d97e4a406f8bb802f51471fc87c8 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2006 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 */
23
24/*
25 * @test
26 * @bug 6475157
27 * @summary Tests deadlock in simultaneous connection and connector-server close
28 * @author Eamonn McManus
29 */
30
31/* This test is somewhat dependent on implementation details. If it suddenly
32 * starts failing after a rewrite of the RMIConnectorServer code, you should
33 * consider whether it is still relevant.
34 */
35
36import java.io.IOException;
37import java.lang.management.ManagementFactory;
38import java.lang.management.ThreadInfo;
39import java.lang.management.ThreadMXBean;
40import java.util.concurrent.Exchanger;
41import javax.management.MBeanServer;
42import javax.management.remote.JMXServiceURL;
43import javax.management.remote.rmi.RMIConnection;
44import javax.management.remote.rmi.RMIConnectorServer;
45import javax.management.remote.rmi.RMIJRMPServerImpl;
46
47public class ConnectorStopDeadlockTest {
48 private static String failure;
49 private static RMIConnectorServer connectorServer;
50
51 public static void main(String[] args) throws Exception {
52 JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://");
53 MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
54 RMIJRMPServerImplSub impl = new RMIJRMPServerImplSub();
55
56 System.out.println("Creating connectorServer");
57 connectorServer = new RMIConnectorServer(url, null, impl, mbs);
58 System.out.println("Starting connectorServer");
59 connectorServer.start();
60 System.out.println("Making client");
61 RMIConnection cc = impl.newClient(null);
62 System.out.println("Closing client");
63 cc.close();
64 if (connectorServer.isActive()) {
65 System.out.println("Stopping connectorServer");
66 connectorServer.stop();
67 }
68 if (failure == null)
69 System.out.println("TEST PASSED, no deadlock");
70 else
71 System.out.println("TEST FAILED");
72 }
73
74 static void fail(Throwable e) {
75 System.out.println("FAILED WITH EXCEPTION: " + e);
76 e.printStackTrace(System.out);
77 failure = e.toString();
78 }
79
80 static void fail(String s) {
81 System.out.println("FAILED: " + s);
82 failure = s;
83 }
84
85// static MonitorInfo[] threadLocks(Thread t) {
86// ThreadMXBean tm = ManagementFactory.getThreadMXBean();
87// ThreadInfo[] tis = tm.getThreadInfo(new long[] {t.getId()}, true, true);
88// if (tis[0] == null)
89// return null;
90// else
91// return tis[0].getLockedMonitors();
92// }
93//
94// static void showLocks(Thread t) {
95// System.out.println("Locks for " + t.getName() + ":");
96// MonitorInfo[] mis = threadLocks(t);
97// if (mis == null)
98// System.out.println(" (no longer exists)");
99// else if (mis.length == 0)
100// System.out.println(" (none)");
101// else {
102// for (MonitorInfo mi : mis)
103// System.out.println(" " + mi);
104// }
105// }
106
107 // Wait until thread t blocks waiting for a lock held by the calling thread,
108 // or until it exits.
109 static void waitForBlock(Thread t) {
110 Thread currentThread = Thread.currentThread();
111 System.out.println("waiting for thread " + t.getName() + " to block " +
112 "on a lock held by thread " + currentThread.getName());
113 ThreadMXBean tm = ManagementFactory.getThreadMXBean();
114 while (true) {
115 ThreadInfo ti = tm.getThreadInfo(t.getId());
116 if (ti == null) {
117 System.out.println(" thread has exited");
118 return;
119 }
120 if (ti.getLockOwnerId() == currentThread.getId()) {
121 System.out.println(" thread now blocked");
122 return;
123 }
124 Thread.yield();
125 }
126 }
127
128 public static class RMIJRMPServerImplSub extends RMIJRMPServerImpl {
129 RMIJRMPServerImplSub() throws IOException {
130 super(0, null, null, null);
131 }
132
133 public RMIConnection makeClient() throws IOException {
134 return super.makeClient("connection id", null);
135 }
136
137 @Override
138 protected void clientClosed(RMIConnection conn) throws IOException {
139 System.out.println("clientClosed, will call connectorServer.stop");
140 final Exchanger<Void> x = new Exchanger<Void>();
141 Thread t = new Thread() {
142 public void run() {
143 try {
144 connectorServer.stop();
145 } catch (Exception e) {
146 fail(e);
147 }
148 }
149 };
150 t.setName("connectorServer.stop");
151 t.start();
152 waitForBlock(t);
153 /* If this thread is synchronized on RMIServerImpl, then
154 * the thread that does connectorServer.stop will acquire
155 * the clientList lock and then block waiting for the RMIServerImpl
156 * lock. Our call to super.clientClosed will then deadlock because
157 * it needs to acquire the clientList lock.
158 */
159 System.out.println("calling super.clientClosed");
160 System.out.flush();
161 super.clientClosed(conn);
162 }
163 }
164}