Path: blob/master/test/jdk/javax/management/remote/mandatory/connection/MultiThreadDeadLockTest.java
41159 views
/*1* Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/222324import java.io.IOException;25import java.io.Serializable;26import java.net.Socket;27import java.rmi.server.RMIClientSocketFactory;28import java.util.HashMap;29import javax.management.MBeanServer;30import javax.management.MBeanServerFactory;31import javax.management.Notification;32import javax.management.NotificationBroadcasterSupport;33import javax.management.NotificationListener;34import javax.management.ObjectName;35import javax.management.remote.JMXConnector;36import javax.management.remote.JMXConnectorFactory;37import javax.management.remote.JMXConnectorServer;38import javax.management.remote.JMXConnectorServerFactory;39import javax.management.remote.JMXServiceURL;40import javax.management.remote.rmi.RMIConnectorServer;4142import jdk.test.lib.Utils;4344/*45* @test46* @bug 669718047* @summary test on a client notification deadlock.48* @author Shanliang JIANG49* @library /test/lib50*51* @run clean MultiThreadDeadLockTest52* @run build MultiThreadDeadLockTest53* @run main MultiThreadDeadLockTest54*/5556public class MultiThreadDeadLockTest {5758private static long serverTimeout = Utils.adjustTimeout(500);5960public static void main(String[] args) throws Exception {61print("Create the MBean server");62MBeanServer mbs = MBeanServerFactory.createMBeanServer();6364print("Initialize environment map");65HashMap env = new HashMap();6667print("Specify a client socket factory to control socket creation.");68env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE,69clientFactory);7071print("Specify a server idle timeout to make a server close an idle connection.");72env.put("jmx.remote.x.server.connection.timeout", serverTimeout);7374print("Disable client heartbeat.");75env.put("jmx.remote.x.client.connection.check.period", 0);7677env.put("jmx.remote.x.notification.fetch.timeout", serverTimeout);7879print("Create an RMI server");80JMXServiceURL url = new JMXServiceURL("rmi", null, 0);81JMXConnectorServer server =82JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);83server.start();8485url = server.getAddress();8687print("Create jmx client on "+url);88StateMachine.setState(CREATE_SOCKET); // allow to create client socket89client = JMXConnectorFactory.connect(url, env);90Thread.sleep(100);9192totoName = new ObjectName("default:name=toto");93mbs.registerMBean(toto, totoName);94print("Register the mbean: " + totoName);9596print("Add listener to toto MBean");97client.getMBeanServerConnection().addNotificationListener(98totoName, myListener, null, null);99Thread.sleep(10);100101print("send notif, listener will block the fetcher");102toto.sendNotif();103Thread.sleep(100);104105StateMachine.setState(NO_OP);106107print("Sleep 3 times of server idle timeout: "+serverTimeout+108", the sever should close the idle connection.");109Thread.sleep(serverTimeout*3);110111print("start the user thread to call mbean method, it will get IOexception" +112" and start the reconnection, the socket factory will block the" +113" socket creation.");114UserThread ut = new UserThread();115ut.start();116Thread.sleep(10);117118print("Free the listener, the fetcher will get IO and makes " +119"a deadlock if the bug is not fixed.");120StateMachine.setState(FREE_LISTENER);121Thread.sleep(100);122123print("Allow to create new socket for the reconnection");124StateMachine.setState(CREATE_SOCKET);125126print("Check whether the user thread gets free to call the mbean.");127if (!ut.waitDone(Utils.adjustTimeout(5000))) {128throw new RuntimeException("Possible deadlock!");129}130131print("Remove the listener.");132client.getMBeanServerConnection().removeNotificationListener(133totoName, myListener, null, null);134Thread.sleep(serverTimeout*3);135136print("\nWell passed, bye!");137138client.close();139Thread.sleep(10);140server.stop();141}142143private static ObjectName totoName = null;144private static JMXConnector client;145146public static class UserThread extends Thread {147public UserThread() {148setDaemon(true);149}150151public void run() {152try {153client.getMBeanServerConnection().invoke(154totoName, "allowReturn", null, null);155} catch (Exception e) {156throw new Error(e);157}158159synchronized(UserThread.class) {160done = true;161UserThread.class.notify();162}163}164165public boolean waitDone(long timeout) {166synchronized(UserThread.class) {167if(!done) {168try {169UserThread.class.wait(timeout);170} catch (Exception e) {171throw new Error(e);172}173}174}175return done;176}177178private boolean done = false;179}180181public static interface TotoMBean {182public void allowReturn();183}184185public static class Toto extends NotificationBroadcasterSupport186implements TotoMBean {187188public void allowReturn() {189enter("allowReturn");190191leave("allowReturn");192}193194public void sendNotif() {195enter("sendNotif");196197sendNotification(new Notification("Toto", totoName, 0));198199leave("sendNotif");200}201}202private static Toto toto = new Toto();203204public static NotificationListener myListener = new NotificationListener() {205public void handleNotification(Notification notification, Object handback) {206enter("handleNotification");207208StateMachine.waitState(FREE_LISTENER);209210leave("handleNotification");211}212};213214public static class RMIClientFactory215implements RMIClientSocketFactory, Serializable {216217public Socket createSocket(String host, int port) throws IOException {218enter("createSocket");219//print("Calling createSocket(" + host + " " + port + ")");220221StateMachine.waitState(CREATE_SOCKET);222Socket s = new Socket(host, port);223leave("createSocket");224225return s;226}227}228private static RMIClientFactory clientFactory = new RMIClientFactory();229230private static int CREATE_SOCKET = 1;231private static int FREE_LISTENER = 3;232private static int NO_OP = 0;233234public static class StateMachine {235236private static int state = NO_OP;237private static int[] lock = new int[0];238239public static void waitState(int s) {240synchronized (lock) {241while (state != s) {242try {243lock.wait();244} catch (InterruptedException ire) {245// should not246throw new Error(ire);247}248}249}250}251252public static int getState() {253synchronized (lock) {254return state;255}256}257258public static void setState(int s) {259synchronized (lock) {260state = s;261lock.notifyAll();262}263}264}265266private static void print(String m) {267System.out.println(m);268}269270private static void enter(String m) {271System.out.println("\n---Enter the method " + m);272}273274private static void leave(String m) {275System.out.println("===Leave the method: " + m);276}277}278279280