8002306: (se) Selector.open fails if invoked with thread interrupt status set [win]
Reviewed-by: alanb
--- a/jdk/src/windows/classes/sun/nio/ch/PipeImpl.java Tue Jan 08 14:54:56 2013 +0800
+++ b/jdk/src/windows/classes/sun/nio/ch/PipeImpl.java Tue Jan 08 20:37:27 2013 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2012, Oracle and/or its affiliates. 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
@@ -72,67 +72,97 @@
private final SelectorProvider sp;
+ private IOException ioe = null;
+
private Initializer(SelectorProvider sp) {
this.sp = sp;
}
+ @Override
public Void run() throws IOException {
- ServerSocketChannel ssc = null;
- SocketChannel sc1 = null;
- SocketChannel sc2 = null;
-
- try {
- // loopback address
- InetAddress lb = InetAddress.getByName("127.0.0.1");
- assert(lb.isLoopbackAddress());
-
- // bind ServerSocketChannel to a port on the loopback address
- ssc = ServerSocketChannel.open();
- ssc.socket().bind(new InetSocketAddress(lb, 0));
-
- // Establish connection (assumes connections are eagerly
- // accepted)
- InetSocketAddress sa
- = new InetSocketAddress(lb, ssc.socket().getLocalPort());
- sc1 = SocketChannel.open(sa);
-
- ByteBuffer bb = ByteBuffer.allocate(8);
- long secret = rnd.nextLong();
- bb.putLong(secret).flip();
- sc1.write(bb);
-
- // Get a connection and verify it is legitimate
+ LoopbackConnector connector = new LoopbackConnector();
+ connector.run();
+ if (ioe instanceof ClosedByInterruptException) {
+ ioe = null;
+ Thread connThread = new Thread(connector) {
+ @Override
+ public void interrupt() {}
+ };
+ connThread.start();
for (;;) {
- sc2 = ssc.accept();
- bb.clear();
- sc2.read(bb);
- bb.rewind();
- if (bb.getLong() == secret)
+ try {
+ connThread.join();
break;
- sc2.close();
+ } catch (InterruptedException ex) {}
}
+ Thread.currentThread().interrupt();
+ }
+
+ if (ioe != null)
+ throw new IOException("Unable to establish loopback connection", ioe);
- // Create source and sink channels
- source = new SourceChannelImpl(sp, sc1);
- sink = new SinkChannelImpl(sp, sc2);
- } catch (IOException e) {
+ return null;
+ }
+
+ private class LoopbackConnector implements Runnable {
+
+ @Override
+ public void run() {
+ ServerSocketChannel ssc = null;
+ SocketChannel sc1 = null;
+ SocketChannel sc2 = null;
+
try {
- if (sc1 != null)
- sc1.close();
- if (sc2 != null)
+ // Loopback address
+ InetAddress lb = InetAddress.getByName("127.0.0.1");
+ assert(lb.isLoopbackAddress());
+ InetSocketAddress sa = null;
+ for(;;) {
+ // Bind ServerSocketChannel to a port on the loopback
+ // address
+ if (ssc == null || !ssc.isOpen()) {
+ ssc = ServerSocketChannel.open();
+ ssc.socket().bind(new InetSocketAddress(lb, 0));
+ sa = new InetSocketAddress(lb, ssc.socket().getLocalPort());
+ }
+
+ // Establish connection (assume connections are eagerly
+ // accepted)
+ sc1 = SocketChannel.open(sa);
+ ByteBuffer bb = ByteBuffer.allocate(8);
+ long secret = rnd.nextLong();
+ bb.putLong(secret).flip();
+ sc1.write(bb);
+
+ // Get a connection and verify it is legitimate
+ sc2 = ssc.accept();
+ bb.clear();
+ sc2.read(bb);
+ bb.rewind();
+ if (bb.getLong() == secret)
+ break;
sc2.close();
- } catch (IOException e2) { }
- IOException x = new IOException("Unable to establish"
- + " loopback connection");
- x.initCause(e);
- throw x;
- } finally {
- try {
- if (ssc != null)
- ssc.close();
- } catch (IOException e2) { }
+ sc1.close();
+ }
+
+ // Create source and sink channels
+ source = new SourceChannelImpl(sp, sc1);
+ sink = new SinkChannelImpl(sp, sc2);
+ } catch (IOException e) {
+ try {
+ if (sc1 != null)
+ sc1.close();
+ if (sc2 != null)
+ sc2.close();
+ } catch (IOException e2) {}
+ ioe = e;
+ } finally {
+ try {
+ if (ssc != null)
+ ssc.close();
+ } catch (IOException e2) {}
+ }
}
- return null;
}
}
@@ -144,7 +174,6 @@
}
}
-
public SourceChannel source() {
return source;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/Pipe/PipeInterrupt.java Tue Jan 08 20:37:27 2013 +0000
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 8002306
+ * @summary Ensure that a Pipe can open even if its thread has already
+ * been interrupted.
+ * @author Dan Xu
+ */
+
+import java.io.IOException;
+import java.nio.channels.Pipe;
+
+
+public class PipeInterrupt {
+
+ private Exception exc = null;
+
+ public static void main(String[] args) throws Exception {
+ PipeInterrupt instance = new PipeInterrupt();
+ instance.test();
+ }
+
+ public void test() throws Exception {
+
+ Thread tester = new Thread("PipeTester") {
+ private Pipe testPipe = null;
+
+ @Override
+ public void run() {
+ for (;;) {
+ boolean interrupted = this.isInterrupted();
+ try {
+ testPipe = Pipe.open();
+ close();
+ if (interrupted) {
+ if (!this.isInterrupted())
+ exc = new RuntimeException("interrupt status reset");
+ break;
+ }
+ } catch (IOException ioe) {
+ exc = ioe;
+ }
+ }
+ }
+
+ private void close() throws IOException {
+ if (testPipe != null) {
+ testPipe.sink().close();
+ testPipe.source().close();
+ }
+ }
+ };
+
+ tester.start();
+ Thread.sleep(200);
+ tester.interrupt();
+ tester.join();
+
+ if (exc != null)
+ throw exc;
+ }
+}