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