diff -r 5d7e5974cb79 -r f5d91fb6df32 jdk/test/javax/management/remote/mandatory/connection/MultiThreadDeadLockTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/remote/mandatory/connection/MultiThreadDeadLockTest.java Mon Sep 22 15:43:12 2008 +0200 @@ -0,0 +1,256 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +import java.io.IOException; +import java.io.Serializable; +import java.net.Socket; +import java.rmi.server.RMIClientSocketFactory; +import java.util.HashMap; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.Notification; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; +import javax.management.remote.rmi.RMIConnectorServer; + +/* + * @test + * @bug 6697180 + * @summary test on a client notification deadlock. + * @author Shanliang JIANG + * @run clean MultiThreadDeadLockTest + * @run build MultiThreadDeadLockTest + * @run main MultiThreadDeadLockTest + */ + +public class MultiThreadDeadLockTest { + + private static long serverTimeout = 500L; + + public static void main(String[] args) throws Exception { + print("Create the MBean server"); + MBeanServer mbs = MBeanServerFactory.createMBeanServer(); + + print("Initialize environment map"); + HashMap env = new HashMap(); + + print("Specify a client socket factory to control socket creation."); + env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, + clientFactory); + + print("Specify a server idle timeout to make a server close an idle connection."); + env.put("jmx.remote.x.server.connection.timeout", serverTimeout); + + print("Disable client heartbeat."); + env.put("jmx.remote.x.client.connection.check.period", 0); + + env.put("jmx.remote.x.notification.fetch.timeout", serverTimeout); + + print("Create an RMI server"); + JMXServiceURL url = new JMXServiceURL("rmi", null, 0); + JMXConnectorServer server = + JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs); + server.start(); + + url = server.getAddress(); + + print("Create jmx client on "+url); + StateMachine.setState(CREATE_SOCKET); // allow to create client socket + client = JMXConnectorFactory.connect(url, env); + Thread.sleep(100); + + totoName = new ObjectName("default:name=toto"); + mbs.registerMBean(toto, totoName); + print("Register the mbean: " + totoName); + + print("Add listener to toto MBean"); + client.getMBeanServerConnection().addNotificationListener( + totoName, myListener, null, null); + Thread.sleep(10); + + print("send notif, listener will block the fetcher"); + toto.sendNotif(); + Thread.sleep(100); + + StateMachine.setState(NO_OP); + + print("Sleep 3 times of server idle timeout: "+serverTimeout+ + ", the sever should close the idle connection."); + Thread.sleep(serverTimeout*3); + + print("start the user thread to call mbean method, it will get IOexception" + + " and start the reconnection, the socket factory will block the" + + " socket creation."); + UserThread ut = new UserThread(); + ut.start(); + Thread.sleep(10); + + print("Free the listener, the fetcher will get IO and makes " + + "a deadlock if the bug is not fixed."); + StateMachine.setState(FREE_LISTENER); + Thread.sleep(100); + + print("Allow to create new socket for the reconnection"); + StateMachine.setState(CREATE_SOCKET); + + print("Check whether the user thread gets free to call the mbean."); + if (!ut.waitDone(5000)) { + throw new RuntimeException("Possible deadlock!"); + } + + print("Remove the listener."); + client.getMBeanServerConnection().removeNotificationListener( + totoName, myListener, null, null); + Thread.sleep(serverTimeout*3); + + print("\nWell passed, bye!"); + + client.close(); + Thread.sleep(10); + server.stop(); + } + + private static ObjectName totoName = null; + private static JMXConnector client; + + public static class UserThread extends Thread { + public UserThread() { + setDaemon(true); + } + + public void run() { + try { + client.getMBeanServerConnection().invoke( + totoName, "allowReturn", null, null); + } catch (Exception e) { + throw new Error(e); + } + + synchronized(UserThread.class) { + done = true; + UserThread.class.notify(); + } + } + + public boolean waitDone(long timeout) { + synchronized(UserThread.class) { + if(!done) { + try { + UserThread.class.wait(timeout); + } catch (Exception e) { + throw new Error(e); + } + } + } + return done; + } + + private boolean done = false; + } + + public static interface TotoMBean { + public void allowReturn(); + } + + public static class Toto extends NotificationBroadcasterSupport + implements TotoMBean { + + public void allowReturn() { + enter("allowReturn"); + + leave("allowReturn"); + } + + public void sendNotif() { + enter("sendNotif"); + + sendNotification(new Notification("Toto", totoName, 0)); + + leave("sendNotif"); + } + } + private static Toto toto = new Toto(); + + public static NotificationListener myListener = new NotificationListener() { + public void handleNotification(Notification notification, Object handback) { + enter("handleNotification"); + + StateMachine.waitState(FREE_LISTENER); + + leave("handleNotification"); + } + }; + + public static class RMIClientFactory + implements RMIClientSocketFactory, Serializable { + + public Socket createSocket(String host, int port) throws IOException { + enter("createSocket"); + //print("Calling createSocket(" + host + " " + port + ")"); + + StateMachine.waitState(CREATE_SOCKET); + Socket s = new Socket(host, port); + leave("createSocket"); + + return s; + } + } + private static RMIClientFactory clientFactory = new RMIClientFactory(); + + private static int CREATE_SOCKET = 1; + private static int FREE_LISTENER = 3; + private static int NO_OP = 0; + + public static class StateMachine { + + private static int state = NO_OP; + private static int[] lock = new int[0]; + + public static void waitState(int s) { + synchronized (lock) { + while (state != s) { + try { + lock.wait(); + } catch (InterruptedException ire) { + // should not + throw new Error(ire); + } + } + } + } + + public static int getState() { + synchronized (lock) { + return state; + } + } + + public static void setState(int s) { + synchronized (lock) { + state = s; + lock.notifyAll(); + } + } + } + + private static void print(String m) { + System.out.println(m); + } + + private static void enter(String m) { + System.out.println("\n---Enter the method " + m); + } + + private static void leave(String m) { + System.out.println("===Leave the method: " + m); + } +} +