1 /* 2 * Copyright (c) 2004, 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 5093922 2120055 27 * @summary Test that NotificationBroadcasterSupport can be subclassed 28 * and used with synchronized(this) without causing deadlock 29 * @author Eamonn McManus 30 * @modules java.management 31 * @run clean BroadcasterSupportDeadlockTest 32 * @run build BroadcasterSupportDeadlockTest 33 * @run main BroadcasterSupportDeadlockTest 34 */ 35 36 import java.lang.management.*; 37 import java.util.concurrent.*; 38 import javax.management.*; 39 40 public class BroadcasterSupportDeadlockTest { 41 public static void main(String[] args) throws Exception { 42 try { 43 Class.forName(ManagementFactory.class.getName()); 44 } catch (Throwable t) { 45 System.out.println("TEST CANNOT RUN: needs JDK 5 at least"); 46 return; 47 } 48 49 final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); 50 final BroadcasterMBean mbean = new Broadcaster(); 51 final ObjectName name = new ObjectName("test:type=Broadcaster"); 52 mbs.registerMBean(mbean, name); 53 54 ThreadMXBean threads = ManagementFactory.getThreadMXBean(); 55 threads.setThreadContentionMonitoringEnabled(true); 56 57 final Semaphore semaphore = new Semaphore(0); 58 59 // Thread 1 - block the Broadcaster 60 Thread t1 = new Thread() { 61 public void run() { 62 try { 63 mbs.invoke(name, "block", 64 new Object[] {semaphore}, 65 new String[] {Semaphore.class.getName()}); 66 } catch (Exception e) { 67 e.printStackTrace(System.out); 68 } finally { 69 System.out.println("TEST INCORRECT: block returned"); 70 System.exit(1); 71 } 72 } 73 }; 74 t1.setDaemon(true); 75 t1.start(); 76 77 /* Wait for Thread 1 to be doing Object.wait(). It's very 78 difficult to synchronize properly here so we wait for the 79 semaphore, then wait a little longer for the mbs.invoke to 80 run, then just in case that isn't enough, we wait for the 81 thread to be in WAITING state. This isn't foolproof, 82 because the machine could be very slow and the 83 Thread.getState() could find the thread in WAITING state 84 due to some operation it does on its way to the one we're 85 interested in. */ 86 semaphore.acquire(); 87 Thread.sleep(100); 88 while (t1.getState() != Thread.State.WAITING) 89 Thread.sleep(1); 90 91 // Thread 2 - try to add a listener 92 final NotificationListener listener = new NotificationListener() { 93 public void handleNotification(Notification n, Object h) {} 94 }; 95 Thread t2 = new Thread() { 96 public void run() { 97 try { 98 mbs.addNotificationListener(name, listener, null, null); 99 } catch (Exception e) { 100 System.out.println("TEST INCORRECT: addNL failed:"); 101 e.printStackTrace(System.out); 102 } 103 } 104 }; 105 t2.setDaemon(true); 106 t2.start(); 107 108 /* Wait for Thread 2 to be blocked on the monitor or to 109 succeed. */ 110 Thread.sleep(100); 111 112 for (int i = 0; i < 1000/*ms*/; i++) { 113 t2.join(1/*ms*/); 114 switch (t2.getState()) { 115 case TERMINATED: 116 System.out.println("TEST PASSED"); 117 return; 118 case BLOCKED: 119 java.util.Map<Thread,StackTraceElement[]> traces = 120 Thread.getAllStackTraces(); 121 showStackTrace("Thread 1", traces.get(t1)); 122 showStackTrace("Thread 2", traces.get(t2)); 123 System.out.println("TEST FAILED: deadlock"); 124 System.exit(1); 125 break; 126 default: 127 break; 128 } 129 } 130 131 System.out.println("TEST FAILED BUT DID NOT NOTICE DEADLOCK"); 132 Thread.sleep(10000); 133 System.exit(1); 134 } 135 136 private static void showStackTrace(String title, 137 StackTraceElement[] stack) { 138 System.out.println("---" + title + "---"); 139 if (stack == null) 140 System.out.println("<no stack trace???>"); 141 else { 142 for (StackTraceElement elmt : stack) 143 System.out.println(" " + elmt); 144 } 145 System.out.println(); 146 } 147 148 public static interface BroadcasterMBean { 149 public void block(Semaphore semaphore); 150 } 151 152 public static class Broadcaster 153 extends NotificationBroadcasterSupport 154 implements BroadcasterMBean { 155 public synchronized void block(Semaphore semaphore) { 156 Object lock = new Object(); 157 synchronized (lock) { 158 try { 159 // Let the caller know that it can now wait for us to 160 // hit the WAITING state 161 semaphore.release(); 162 lock.wait(); // block forever 163 } catch (InterruptedException e) { 164 System.out.println("TEST INCORRECT: lock interrupted:"); 165 e.printStackTrace(System.out); 166 System.exit(1); 167 } 168 } 169 } 170 } 171 }