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