0N/A/*
2362N/A * Copyright (c) 2004, 2005, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
0N/A * published by the Free Software Foundation.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A/*
0N/A * @test
0N/A * @bug 5093922 2120055
0N/A * @summary Test that NotificationBroadcasterSupport can be subclassed
0N/A * and used with synchronized(this) without causing deadlock
0N/A * @author Eamonn McManus
0N/A * @run clean BroadcasterSupportDeadlockTest
0N/A * @run build BroadcasterSupportDeadlockTest
0N/A * @run main BroadcasterSupportDeadlockTest
0N/A */
0N/A
0N/Aimport java.lang.management.*;
0N/Aimport java.util.concurrent.*;
0N/Aimport javax.management.*;
0N/A
0N/Apublic class BroadcasterSupportDeadlockTest {
0N/A public static void main(String[] args) throws Exception {
0N/A try {
0N/A Class.forName(ManagementFactory.class.getName());
0N/A } catch (Throwable t) {
0N/A System.out.println("TEST CANNOT RUN: needs JDK 5 at least");
0N/A return;
0N/A }
0N/A
0N/A final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
0N/A final BroadcasterMBean mbean = new Broadcaster();
0N/A final ObjectName name = new ObjectName("test:type=Broadcaster");
0N/A mbs.registerMBean(mbean, name);
0N/A
0N/A ThreadMXBean threads = ManagementFactory.getThreadMXBean();
0N/A threads.setThreadContentionMonitoringEnabled(true);
0N/A
0N/A final Semaphore semaphore = new Semaphore(0);
0N/A
0N/A // Thread 1 - block the Broadcaster
0N/A Thread t1 = new Thread() {
0N/A public void run() {
0N/A try {
0N/A mbs.invoke(name, "block",
0N/A new Object[] {semaphore},
0N/A new String[] {Semaphore.class.getName()});
0N/A } catch (Exception e) {
0N/A e.printStackTrace(System.out);
0N/A } finally {
0N/A System.out.println("TEST INCORRECT: block returned");
0N/A System.exit(1);
0N/A }
0N/A }
0N/A };
0N/A t1.setDaemon(true);
0N/A t1.start();
0N/A
0N/A /* Wait for Thread 1 to be doing Object.wait(). It's very
0N/A difficult to synchronize properly here so we wait for the
0N/A semaphore, then wait a little longer for the mbs.invoke to
0N/A run, then just in case that isn't enough, we wait for the
0N/A thread to be in WAITING state. This isn't foolproof,
0N/A because the machine could be very slow and the
0N/A Thread.getState() could find the thread in WAITING state
0N/A due to some operation it does on its way to the one we're
0N/A interested in. */
0N/A semaphore.acquire();
0N/A Thread.sleep(100);
0N/A while (t1.getState() != Thread.State.WAITING)
0N/A Thread.sleep(1);
0N/A
0N/A // Thread 2 - try to add a listener
0N/A final NotificationListener listener = new NotificationListener() {
0N/A public void handleNotification(Notification n, Object h) {}
0N/A };
0N/A Thread t2 = new Thread() {
0N/A public void run() {
0N/A try {
0N/A mbs.addNotificationListener(name, listener, null, null);
0N/A } catch (Exception e) {
0N/A System.out.println("TEST INCORRECT: addNL failed:");
0N/A e.printStackTrace(System.out);
0N/A }
0N/A }
0N/A };
0N/A t2.setDaemon(true);
0N/A t2.start();
0N/A
0N/A /* Wait for Thread 2 to be blocked on the monitor or to
0N/A succeed. */
0N/A Thread.sleep(100);
0N/A
0N/A for (int i = 0; i < 1000/*ms*/; i++) {
0N/A t2.join(1/*ms*/);
0N/A switch (t2.getState()) {
0N/A case TERMINATED:
0N/A System.out.println("TEST PASSED");
0N/A return;
0N/A case BLOCKED:
0N/A java.util.Map<Thread,StackTraceElement[]> traces =
0N/A Thread.getAllStackTraces();
0N/A showStackTrace("Thread 1", traces.get(t1));
0N/A showStackTrace("Thread 2", traces.get(t2));
0N/A System.out.println("TEST FAILED: deadlock");
0N/A System.exit(1);
0N/A break;
0N/A default:
0N/A break;
0N/A }
0N/A }
0N/A
0N/A System.out.println("TEST FAILED BUT DID NOT NOTICE DEADLOCK");
0N/A Thread.sleep(10000);
0N/A System.exit(1);
0N/A }
0N/A
0N/A private static void showStackTrace(String title,
0N/A StackTraceElement[] stack) {
0N/A System.out.println("---" + title + "---");
0N/A if (stack == null)
0N/A System.out.println("<no stack trace???>");
0N/A else {
0N/A for (StackTraceElement elmt : stack)
0N/A System.out.println(" " + elmt);
0N/A }
0N/A System.out.println();
0N/A }
0N/A
0N/A public static interface BroadcasterMBean {
0N/A public void block(Semaphore semaphore);
0N/A }
0N/A
0N/A public static class Broadcaster
0N/A extends NotificationBroadcasterSupport
0N/A implements BroadcasterMBean {
0N/A public synchronized void block(Semaphore semaphore) {
0N/A Object lock = new Object();
0N/A synchronized (lock) {
0N/A try {
0N/A // Let the caller know that it can now wait for us to
0N/A // hit the WAITING state
0N/A semaphore.release();
0N/A lock.wait(); // block forever
0N/A } catch (InterruptedException e) {
0N/A System.out.println("TEST INCORRECT: lock interrupted:");
0N/A e.printStackTrace(System.out);
0N/A System.exit(1);
0N/A }
0N/A }
0N/A }
0N/A }
0N/A}