OpenJDK / jdk / jdk
changeset 1706:4a382455c04d
6760712: Provide a connector server option that causes it not to prevent the VM from exiting
Reviewed-by: emcmanus
author | sjiang |
---|---|
date | Tue, 09 Dec 2008 18:42:13 +0100 |
parents | aef312419918 |
children | f6c20f760c59 |
files | jdk/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java jdk/src/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java jdk/test/javax/management/remote/mandatory/connection/DaemonRMIExporterTest.java |
diffstat | 3 files changed, 164 insertions(+), 4 deletions(-) [+] |
line wrap: on
line diff
--- a/jdk/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java Fri Dec 05 21:59:09 2008 -0800 +++ b/jdk/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java Tue Dec 09 18:42:13 2008 +0100 @@ -1,3 +1,4 @@ + /* * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -798,6 +799,24 @@ JMXConnectorServer.DELEGATE_TO_EVENT_SERVICE, true, true); } + /** + * <p>Name of the attribute that specifies whether a connector server + * should not prevent the VM from exiting + */ + public static final String JMX_SERVER_DAEMON = "jmx.remote.x.daemon"; + + /** + * Returns true if {@value SERVER_DAEMON} is specified in the {@code env} + * as a key and its value is a String and it is equal to true ignoring case. + * + * @param env + * @return + */ + public static boolean isServerDaemon(Map env) { + return (env != null) && + ("true".equalsIgnoreCase((String)env.get(JMX_SERVER_DAEMON))); + } + // /** // * <p>Name of the attribute that specifies an EventRelay object to use. // */
--- a/jdk/src/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java Fri Dec 05 21:59:09 2008 -0800 +++ b/jdk/src/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java Tue Dec 09 18:42:13 2008 +0100 @@ -38,6 +38,9 @@ import javax.security.auth.Subject; import com.sun.jmx.remote.internal.RMIExporter; +import com.sun.jmx.remote.util.EnvHelp; +import sun.rmi.server.UnicastServerRef; +import sun.rmi.server.UnicastServerRef2; /** * <p>An {@link RMIServer} object that is exported through JRMP and that @@ -93,12 +96,27 @@ } private void export(Remote obj) throws RemoteException { - RMIExporter exporter = + final RMIExporter exporter = (RMIExporter) env.get(RMIExporter.EXPORTER_ATTRIBUTE); - if (exporter == null) + final boolean daemon = EnvHelp.isServerDaemon(env); + + if (daemon && exporter != null) { + throw new IllegalArgumentException("If "+EnvHelp.JMX_SERVER_DAEMON+ + " is specified as true, "+RMIExporter.EXPORTER_ATTRIBUTE+ + " cannot be used to specify an exporter!"); + } + + if (daemon) { + if (csf == null && ssf == null) { + new UnicastServerRef(port).exportObject(obj, null, true); + } else { + new UnicastServerRef2(port, csf, ssf).exportObject(obj, null, true); + } + } else if (exporter != null) { + exporter.exportObject(obj, port, csf, ssf); + } else { UnicastRemoteObject.exportObject(obj, port, csf, ssf); - else - exporter.exportObject(obj, port, csf, ssf); + } } private void unexport(Remote obj, boolean force)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/remote/mandatory/connection/DaemonRMIExporterTest.java Tue Dec 09 18:42:13 2008 +0100 @@ -0,0 +1,123 @@ +/* + * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + + +/* + * @test + * @bug 6760712 + * @summary test the connector server option that causes it not to prevent the + * VM from exiting + * @author Shanliang JIANG, Eamonn McManus + * @run main/othervm DaemonRMIExporterTest + */ +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import javax.management.MBeanServerFactory; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; + +// Test the connector server option that causes it not to prevent the VM +// from exiting. It's tricky to test exactly that, though possible. If +// we're being run from within jtreg, then jtreg has threads of its own +// that will prevent the VM from exiting. What's more it will kill all +// threads that the test created as soon as the main method returns, +// including the ones that would prevent the VM from exiting without the +// special option. +// Here we check that the test code does not create +// any permanent non-daemon threads, by recording the initial set of +// non-daemon threads (including at least one from jtreg), doing our stuff, +// then waiting for there to be no non-daemon threads that were not in +// the initial set. +public class DaemonRMIExporterTest { + public static void main(String[] args) throws Exception { + Set<Thread> initialNonDaemonThreads = getNonDaemonThreads(); + + JMXServiceURL addr = new JMXServiceURL("rmi", null, 0); + System.out.println("DaemonRMIExporterTest: Creating a RMIConnectorServer on " + addr); + Map<String, ?> env = + Collections.singletonMap("jmx.remote.x.daemon", "true"); + JMXConnectorServer server = + JMXConnectorServerFactory.newJMXConnectorServer(addr, + env, + MBeanServerFactory.createMBeanServer()); + server.start(); + System.out.println("DaemonRMIExporterTest: Started the server on " + server.getAddress()); + + System.out.println("DaemonRMIExporterTest: Connecting a client to the server ..."); + final JMXConnector conn = JMXConnectorFactory.connect(server.getAddress()); + conn.getMBeanServerConnection().getDefaultDomain(); + + System.out.println("DaemonRMIExporterTest: Closing the client ..."); + conn.close(); + + System.out.println("DaemonRMIExporterTest No more user code to execute, the VM should " + + "exit normally, otherwise will be blocked forever if the bug is not fixed."); + + long deadline = System.currentTimeMillis() + 10000; + ok: { + while (System.currentTimeMillis() < deadline) { + Set<Thread> nonDaemonThreads = getNonDaemonThreads(); + nonDaemonThreads.removeAll(initialNonDaemonThreads); + if (nonDaemonThreads.isEmpty()) + break ok; + System.out.println("Non-daemon threads: " + nonDaemonThreads); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + throw new AssertionError(e); + } + } + throw new Exception("TEST FAILED: non-daemon threads remain"); + } + + System.out.println("TEST PASSED"); + } + + private static Set<Thread> getNonDaemonThreads() { + ThreadGroup tg = Thread.currentThread().getThreadGroup(); + while (tg.getParent() != null) + tg = tg.getParent(); + Thread[] threads = null; + for (int size = 10; size < 10000; size *= 2) { + threads = new Thread[size]; + int n = tg.enumerate(threads, true); + if (n < size) { + threads = Arrays.copyOf(threads, n); + break; + } + } + Set<Thread> ndThreads = new HashSet<Thread>(); + for (Thread t : threads) { + if (!t.isDaemon()) + ndThreads.add(t); + } + return ndThreads; + } +}