--- old/test/java/rmi/testlibrary/RMID.java 2016-10-03 15:48:37.953635450 +0100 +++ new/test/java/rmi/testlibrary/RMID.java 2016-10-03 15:48:37.793638846 +0100 @@ -22,6 +22,17 @@ */ import java.io.*; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ProtocolFamily; +import java.net.ServerSocket; +import java.nio.channels.Channel; +import java.nio.channels.DatagramChannel; +import java.nio.channels.Pipe; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.nio.channels.spi.AbstractSelector; +import java.nio.channels.spi.SelectorProvider; import java.rmi.*; import java.rmi.activation.*; import java.rmi.registry.*; @@ -49,8 +60,14 @@ public static String MANAGER_OPTION="-Djava.security.manager="; - /** Test port for rmid */ - private final int port; + /** + * Test port for rmid. + * + * May initially be 0, which means that the child rmid process will choose + * an ephemeral port and report it back to the parent process. This field + * will then be set to the child rmid's ephemeral port value. + */ + private volatile int port; /** Initial log name */ protected static String log = "log"; @@ -62,7 +79,7 @@ } /** make test options and arguments */ - private static String makeOptions(boolean debugExec) { + private static String makeOptions(int port, boolean debugExec) { String options = " -Dsun.rmi.server.activation.debugExec=" + debugExec; @@ -87,6 +104,18 @@ // to avoid spurious timeouts on slow machines. options += " -Dsun.rmi.activation.execTimeout=60000"; + // Disable redirection of System.err to /tmp, even when using the + // inheritChannel mechanism. + options += " -Dsun.rmi.server.activation.disableErrRedirect"; + + if (port == 0) { + // Ephemeral port, so have the rmid child process create the + // server socket channel and report its port number, over stdin. + options += " -classpath " + TestParams.testClassPath; + options += " --add-exports=java.base/sun.nio.ch=ALL-UNNAMED"; + options += " -Djava.nio.channels.spi.SelectorProvider=RMID$RMIDSelectorProvider"; + } + return options; } @@ -107,7 +136,8 @@ String args = " -log " + (new File(LOGDIR, log)).getAbsolutePath(); - if (includePortArg) { + // 0 = ephemeral port, do no include an explicit port number + if (includePortArg && port != 0) { args += " -port " + port; } @@ -160,7 +190,7 @@ boolean debugExec, boolean includePortArg, int port) { - String options = makeOptions(debugExec); + String options = makeOptions(port, debugExec); String args = makeArgs(includePortArg, port); RMID rmid = new RMID("sun.rmi.server.Activation", options, args, out, err, port); @@ -169,6 +199,17 @@ return rmid; } + public static RMID createRMIDOnEphemeralPort() { + return createRMID(System.out, System.err, true, true, 0); + } + + public static RMID createRMIDOnEphemeralPort(OutputStream out, + OutputStream err, + boolean debugExec) + { + return createRMID(out, err, debugExec, true, 0); + } + /** * Private constructor. RMID instances should be created @@ -247,7 +288,10 @@ // a well recognized exception (port already in use...). mesg("Starting rmid on port " + port + "."); - super.start(); + int p = super.startAndGetPort(); + if (p != -1) + port = p; + mesg("Started rmid on port " + port + "."); // int slopFactor = 1; // try { @@ -271,8 +315,11 @@ try { int status = vm.exitValue(); + waitFor(TIMEOUT_SHUTDOWN_MS); TestLibrary.bomb("Rmid process exited with status " + status + " after " + (System.currentTimeMillis() - startTime) + "ms."); + } catch (InterruptedException | TimeoutException e) { + mesg(e); } catch (IllegalThreadStateException ignore) { } // The rmid process is alive; check to see whether @@ -307,6 +354,8 @@ */ public void restart() throws IOException { destroy(); + options = makeOptions(port, true); + args = makeArgs(true, port); start(); } @@ -401,4 +450,68 @@ public int getPort() { return port; } + + + /** + * A SelectorProvider, that can be loaded by the child rmid process, whose + * inheritedChannel method will create a new server socket channel and + * report it back to the parent process, over stdout. + */ + public static class RMIDSelectorProvider extends SelectorProvider { + + private final SelectorProvider provider; + private ServerSocketChannel channel; + + public RMIDSelectorProvider() { + provider = sun.nio.ch.DefaultSelectorProvider.create(); + } + + public DatagramChannel openDatagramChannel() + throws IOException + { + return provider.openDatagramChannel(); + } + + public DatagramChannel openDatagramChannel(ProtocolFamily family) + throws IOException + { + return provider.openDatagramChannel(family); + } + + public Pipe openPipe() + throws IOException + { + return provider.openPipe(); + } + + public AbstractSelector openSelector() + throws IOException + { + return provider.openSelector(); + } + + public ServerSocketChannel openServerSocketChannel() + throws IOException + { + return provider.openServerSocketChannel(); + } + + public SocketChannel openSocketChannel() + throws IOException + { + return provider.openSocketChannel(); + } + + public static final String MESSAGE = "RmidSelectorProvider-listening On:"; + + public synchronized Channel inheritedChannel() throws IOException { + System.out.println("RMIDSelectorProvider.inheritedChannel"); + if (channel == null) { + // Create and bind a new server socket channel + channel = ServerSocketChannel.open().bind(new InetSocketAddress(0)); + System.out.println(MESSAGE + channel.socket().getLocalPort()); + } + return channel; + } + } }