/* * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /* * @test * @bug 4757273 * @summary Test deadlock in MBeanServerDelegate listeners * @author Eamonn McManus * @modules java.management * @run clean NotifDeadlockTest * @run build NotifDeadlockTest * @run main NotifDeadlockTest */ /* * Test deadlock when a listener for an MBeanServerDelegate does a * register or unregister of an MBean. Since such a listener is * triggered by a register or unregister operation, deadlock scenarios * are possible if there are any locks held while the listener is * being dispatched. * * The flow of control looks rather like this: * * Thread 1: * - MBeanServer.createMBean(..., objectName1); * --- MBeanServerDelegate.sendNotification * ----- XListener.handleNotification * ------- create Thread 2 * ------- wait for Thread 2 to complete * * Thread 2: * - MBeanServer.createMBean(..., objectName2); * - end Thread 2 * * If any locks are held by Thread 1 within createMBean or * sendNotification, then Thread 2 can block waiting for them. * Since Thread 1 is itself waiting for Thread 2, this is a deadlock. * * We test all four combinations of: * (Thread1-create,Thread1-unregister) x (Thread2-create,Thread2-unregister) * * In the JMX 1.1 RI, all four tests fail. In the JMX 1.2 RI, all four * tests should pass. */ import javax.management.*; public class NotifDeadlockTest { static ObjectName on1, on2, delName; static { try { on1 = new ObjectName("thing:a=b"); on2 = new ObjectName("thing:c=d"); delName = new ObjectName("JMImplementation:type=MBeanServerDelegate"); } catch (MalformedObjectNameException e) { throw new Error(); } } static MBeanServer mbs; static boolean timedOut; /* This listener registers or unregisters the MBean called on2 when triggered. */ private static class XListener implements NotificationListener { private boolean firstTime = true; private final boolean register; XListener(boolean register) { this.register = register; } public void handleNotification(Notification not, Object handback) { if (firstTime) { firstTime = false; Thread t = new Thread() { public void run() { try { if (register) { mbs.createMBean("javax.management.timer.Timer", on2); System.out.println("Listener created " + on2); } else { mbs.unregisterMBean(on2); System.out.println("Listener removed " + on2); } } catch (Exception e) { e.printStackTrace(); } } }; t.start(); try { t.join(2000); } catch (InterruptedException e) { e.printStackTrace(); // should not happen } if (t.isAlive()) { System.out.println("FAILURE: Wait timed out: " + "probable deadlock"); timedOut = true; } } } } public static void main(String[] args) throws Exception { boolean success = true; System.out.println("Test 1: in register notif, unregister an MBean"); timedOut = false; mbs = MBeanServerFactory.createMBeanServer(); mbs.createMBean("javax.management.timer.Timer", on2); mbs.addNotificationListener(delName, new XListener(false), null, null); mbs.createMBean("javax.management.timer.Timer", on1); MBeanServerFactory.releaseMBeanServer(mbs); if (timedOut) { success = false; Thread.sleep(500); // wait for the spawned thread to complete its work, probably } System.out.println("Test 1 completed"); System.out.println("Test 2: in unregister notif, unregister an MBean"); timedOut = false; mbs = MBeanServerFactory.createMBeanServer(); mbs.createMBean("javax.management.timer.Timer", on1); mbs.createMBean("javax.management.timer.Timer", on2); mbs.addNotificationListener(delName, new XListener(false), null, null); mbs.unregisterMBean(on1); MBeanServerFactory.releaseMBeanServer(mbs); if (timedOut) { success = false; Thread.sleep(500); // wait for the spawned thread to complete its work, probably } System.out.println("Test 2 completed"); System.out.println("Test 3: in register notif, register an MBean"); timedOut = false; mbs = MBeanServerFactory.createMBeanServer(); mbs.addNotificationListener(delName, new XListener(true), null, null); mbs.createMBean("javax.management.timer.Timer", on1); MBeanServerFactory.releaseMBeanServer(mbs); if (timedOut) { success = false; Thread.sleep(500); // wait for the spawned thread to complete its work, probably } System.out.println("Test 3 completed"); System.out.println("Test 4: in unregister notif, register an MBean"); timedOut = false; mbs = MBeanServerFactory.createMBeanServer(); mbs.createMBean("javax.management.timer.Timer", on1); mbs.addNotificationListener(delName, new XListener(true), null, null); mbs.unregisterMBean(on1); MBeanServerFactory.releaseMBeanServer(mbs); if (timedOut) { success = false; Thread.sleep(500); // wait for the spawned thread to complete its work, probably } System.out.println("Test 4 completed"); if (success) System.out.println("Test passed"); else { System.out.println("TEST FAILED: at least one subcase failed"); System.exit(1); } } }