blob: ad3bb88a63b8cae930692335603c78f0cbe753b6 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003 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 4757273
27 * @summary Test deadlock in MBeanServerDelegate listeners
28 * @author Eamonn McManus
29 * @run clean NotifDeadlockTest
30 * @run build NotifDeadlockTest
31 * @run main NotifDeadlockTest
32 */
33
34/*
35 * Test deadlock when a listener for an MBeanServerDelegate does a
36 * register or unregister of an MBean. Since such a listener is
37 * triggered by a register or unregister operation, deadlock scenarios
38 * are possible if there are any locks held while the listener is
39 * being dispatched.
40 *
41 * The flow of control looks rather like this:
42 *
43 * Thread 1:
44 * - MBeanServer.createMBean(..., objectName1);
45 * --- MBeanServerDelegate.sendNotification
46 * ----- XListener.handleNotification
47 * ------- create Thread 2
48 * ------- wait for Thread 2 to complete
49 *
50 * Thread 2:
51 * - MBeanServer.createMBean(..., objectName2);
52 * - end Thread 2
53 *
54 * If any locks are held by Thread 1 within createMBean or
55 * sendNotification, then Thread 2 can block waiting for them.
56 * Since Thread 1 is itself waiting for Thread 2, this is a deadlock.
57 *
58 * We test all four combinations of:
59 * (Thread1-create,Thread1-unregister) x (Thread2-create,Thread2-unregister)
60 *
61 * In the JMX 1.1 RI, all four tests fail. In the JMX 1.2 RI, all four
62 * tests should pass.
63 */
64import javax.management.*;
65
66public class NotifDeadlockTest {
67 static ObjectName on1, on2, delName;
68 static {
69 try {
70 on1 = new ObjectName("thing:a=b");
71 on2 = new ObjectName("thing:c=d");
72 delName =
73 new ObjectName("JMImplementation:type=MBeanServerDelegate");
74 } catch (MalformedObjectNameException e) {
75 throw new Error();
76 }
77 }
78 static MBeanServer mbs;
79 static boolean timedOut;
80
81 /* This listener registers or unregisters the MBean called on2
82 when triggered. */
83 private static class XListener implements NotificationListener {
84 private boolean firstTime = true;
85 private final boolean register;
86
87 XListener(boolean register) {
88 this.register = register;
89 }
90
91 public void handleNotification(Notification not, Object handback) {
92 if (firstTime) {
93 firstTime = false;
94 Thread t = new Thread() {
95 public void run() {
96 try {
97 if (register) {
98 mbs.createMBean("javax.management.timer.Timer",
99 on2);
100 System.out.println("Listener created " + on2);
101 } else {
102 mbs.unregisterMBean(on2);
103 System.out.println("Listener removed " + on2);
104 }
105 } catch (Exception e) {
106 e.printStackTrace();
107 }
108 }
109 };
110 t.start();
111 try {
112 t.join(2000);
113 } catch (InterruptedException e) {
114 e.printStackTrace(); // should not happen
115 }
116 if (t.isAlive()) {
117 System.out.println("FAILURE: Wait timed out: " +
118 "probable deadlock");
119 timedOut = true;
120 }
121 }
122 }
123 }
124
125 public static void main(String[] args) throws Exception {
126 boolean success = true;
127
128 System.out.println("Test 1: in register notif, unregister an MBean");
129 timedOut = false;
130 mbs = MBeanServerFactory.createMBeanServer();
131 mbs.createMBean("javax.management.timer.Timer", on2);
132 mbs.addNotificationListener(delName, new XListener(false), null, null);
133 mbs.createMBean("javax.management.timer.Timer", on1);
134 MBeanServerFactory.releaseMBeanServer(mbs);
135 if (timedOut) {
136 success = false;
137 Thread.sleep(500);
138 // wait for the spawned thread to complete its work, probably
139 }
140 System.out.println("Test 1 completed");
141
142 System.out.println("Test 2: in unregister notif, unregister an MBean");
143 timedOut = false;
144 mbs = MBeanServerFactory.createMBeanServer();
145 mbs.createMBean("javax.management.timer.Timer", on1);
146 mbs.createMBean("javax.management.timer.Timer", on2);
147 mbs.addNotificationListener(delName, new XListener(false), null, null);
148 mbs.unregisterMBean(on1);
149 MBeanServerFactory.releaseMBeanServer(mbs);
150 if (timedOut) {
151 success = false;
152 Thread.sleep(500);
153 // wait for the spawned thread to complete its work, probably
154 }
155 System.out.println("Test 2 completed");
156
157 System.out.println("Test 3: in register notif, register an MBean");
158 timedOut = false;
159 mbs = MBeanServerFactory.createMBeanServer();
160 mbs.addNotificationListener(delName, new XListener(true), null, null);
161 mbs.createMBean("javax.management.timer.Timer", on1);
162 MBeanServerFactory.releaseMBeanServer(mbs);
163 if (timedOut) {
164 success = false;
165 Thread.sleep(500);
166 // wait for the spawned thread to complete its work, probably
167 }
168 System.out.println("Test 3 completed");
169
170 System.out.println("Test 4: in unregister notif, register an MBean");
171 timedOut = false;
172 mbs = MBeanServerFactory.createMBeanServer();
173 mbs.createMBean("javax.management.timer.Timer", on1);
174 mbs.addNotificationListener(delName, new XListener(true), null, null);
175 mbs.unregisterMBean(on1);
176 MBeanServerFactory.releaseMBeanServer(mbs);
177 if (timedOut) {
178 success = false;
179 Thread.sleep(500);
180 // wait for the spawned thread to complete its work, probably
181 }
182 System.out.println("Test 4 completed");
183
184 if (success)
185 System.out.println("Test passed");
186 else {
187 System.out.println("TEST FAILED: at least one subcase failed");
188 System.exit(1);
189 }
190 }
191}