1 /* 2 * To change this template, choose Tools | Templates 3 * and open the template in the editor. 4 */ 5 6 import java.io.IOException; 7 import java.io.Serializable; 8 import java.net.Socket; 9 import java.rmi.server.RMIClientSocketFactory; 10 import java.util.HashMap; 11 import javax.management.MBeanServer; 12 import javax.management.MBeanServerFactory; 13 import javax.management.Notification; 14 import javax.management.NotificationBroadcasterSupport; 15 import javax.management.NotificationListener; 16 import javax.management.ObjectName; 17 import javax.management.remote.JMXConnector; 18 import javax.management.remote.JMXConnectorFactory; 19 import javax.management.remote.JMXConnectorServer; 20 import javax.management.remote.JMXConnectorServerFactory; 21 import javax.management.remote.JMXServiceURL; 22 import javax.management.remote.rmi.RMIConnectorServer; 23 24 /* 25 * @test 26 * @bug 6697180 27 * @summary test on a client notification deadlock. 28 * @author Shanliang JIANG 29 * @run clean MultiThreadDeadLockTest 30 * @run build MultiThreadDeadLockTest 31 * @run main MultiThreadDeadLockTest 32 */ 33 34 public class MultiThreadDeadLockTest { 35 36 private static long serverTimeout = 500L; 37 38 public static void main(String[] args) throws Exception { 39 print("Create the MBean server"); 40 MBeanServer mbs = MBeanServerFactory.createMBeanServer(); 41 42 print("Initialize environment map"); 43 HashMap env = new HashMap(); 44 45 print("Specify a client socket factory to control socket creation."); 46 env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, 47 clientFactory); 48 49 print("Specify a server idle timeout to make a server close an idle connection."); 50 env.put("jmx.remote.x.server.connection.timeout", serverTimeout); 51 52 print("Disable client heartbeat."); 53 env.put("jmx.remote.x.client.connection.check.period", 0); 54 55 env.put("jmx.remote.x.notification.fetch.timeout", serverTimeout); 56 57 print("Create an RMI server"); 58 JMXServiceURL url = new JMXServiceURL("rmi", null, 0); 59 JMXConnectorServer server = 60 JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs); 61 server.start(); 62 63 url = server.getAddress(); 64 65 print("Create jmx client on "+url); 66 StateMachine.setState(CREATE_SOCKET); // allow to create client socket 67 client = JMXConnectorFactory.connect(url, env); 68 Thread.sleep(100); 69 70 totoName = new ObjectName("default:name=toto"); 71 mbs.registerMBean(toto, totoName); 72 print("Register the mbean: " + totoName); 73 74 print("Add listener to toto MBean"); 75 client.getMBeanServerConnection().addNotificationListener( 76 totoName, myListener, null, null); 77 Thread.sleep(10); 78 79 print("send notif, listener will block the fetcher"); 80 toto.sendNotif(); 81 Thread.sleep(100); 82 83 StateMachine.setState(NO_OP); 84 85 print("Sleep 3 times of server idle timeout: "+serverTimeout+ 86 ", the sever should close the idle connection."); 87 Thread.sleep(serverTimeout*3); 88 89 print("start the user thread to call mbean method, it will get IOexception" + 90 " and start the reconnection, the socket factory will block the" + 91 " socket creation."); 92 UserThread ut = new UserThread(); 93 ut.start(); 94 Thread.sleep(10); 95 96 print("Free the listener, the fetcher will get IO and makes " + 97 "a deadlock if the bug is not fixed."); 98 StateMachine.setState(FREE_LISTENER); 99 Thread.sleep(100); 100 101 print("Allow to create new socket for the reconnection"); 102 StateMachine.setState(CREATE_SOCKET); 103 104 print("Check whether the user thread gets free to call the mbean."); 105 if (!ut.waitDone(5000)) { 106 throw new RuntimeException("Possible deadlock!"); 107 } 108 109 print("Remove the listener."); 110 client.getMBeanServerConnection().removeNotificationListener( 111 totoName, myListener, null, null); 112 Thread.sleep(serverTimeout*3); 113 114 print("\nWell passed, bye!"); 115 116 client.close(); 117 Thread.sleep(10); 118 server.stop(); 119 } 120 121 private static ObjectName totoName = null; 122 private static JMXConnector client; 123 124 public static class UserThread extends Thread { 125 public UserThread() { 126 setDaemon(true); 127 } 128 129 public void run() { 130 try { 131 client.getMBeanServerConnection().invoke( 132 totoName, "allowReturn", null, null); 133 } catch (Exception e) { 134 throw new Error(e); 135 } 136 137 synchronized(UserThread.class) { 138 done = true; 139 UserThread.class.notify(); 140 } 141 } 142 143 public boolean waitDone(long timeout) { 144 synchronized(UserThread.class) { 145 if(!done) { 146 try { 147 UserThread.class.wait(timeout); 148 } catch (Exception e) { 149 throw new Error(e); 150 } 151 } 152 } 153 return done; 154 } 155 156 private boolean done = false; 157 } 158 159 public static interface TotoMBean { 160 public void allowReturn(); 161 } 162 163 public static class Toto extends NotificationBroadcasterSupport 164 implements TotoMBean { 165 166 public void allowReturn() { 167 enter("allowReturn"); 168 169 leave("allowReturn"); 170 } 171 172 public void sendNotif() { 173 enter("sendNotif"); 174 175 sendNotification(new Notification("Toto", totoName, 0)); 176 177 leave("sendNotif"); 178 } 179 } 180 private static Toto toto = new Toto(); 181 182 public static NotificationListener myListener = new NotificationListener() { 183 public void handleNotification(Notification notification, Object handback) { 184 enter("handleNotification"); 185 186 StateMachine.waitState(FREE_LISTENER); 187 188 leave("handleNotification"); 189 } 190 }; 191 192 public static class RMIClientFactory 193 implements RMIClientSocketFactory, Serializable { 194 195 public Socket createSocket(String host, int port) throws IOException { 196 enter("createSocket"); 197 //print("Calling createSocket(" + host + " " + port + ")"); 198 199 StateMachine.waitState(CREATE_SOCKET); 200 Socket s = new Socket(host, port); 201 leave("createSocket"); 202 203 return s; 204 } 205 } 206 private static RMIClientFactory clientFactory = new RMIClientFactory(); 207 208 private static int CREATE_SOCKET = 1; 209 private static int FREE_LISTENER = 3; 210 private static int NO_OP = 0; 211 212 public static class StateMachine { 213 214 private static int state = NO_OP; 215 private static int[] lock = new int[0]; 216 217 public static void waitState(int s) { 218 synchronized (lock) { 219 while (state != s) { 220 try { 221 lock.wait(); 222 } catch (InterruptedException ire) { 223 // should not 224 throw new Error(ire); 225 } 226 } 227 } 228 } 229 230 public static int getState() { 231 synchronized (lock) { 232 return state; 233 } 234 } 235 236 public static void setState(int s) { 237 synchronized (lock) { 238 state = s; 239 lock.notifyAll(); 240 } 241 } 242 } 243 244 private static void print(String m) { 245 System.out.println(m); 246 } 247 248 private static void enter(String m) { 249 System.out.println("\n---Enter the method " + m); 250 } 251 252 private static void leave(String m) { 253 System.out.println("===Leave the method: " + m); 254 } 255 }