8002306: (se) Selector.open fails if invoked with thread interrupt status set [win]
authordxu
Tue, 08 Jan 2013 20:37:27 +0000
changeset 15007 31d8a6072b16
parent 15006 10d6aacdd67f
child 15011 ca5fca41f778
8002306: (se) Selector.open fails if invoked with thread interrupt status set [win] Reviewed-by: alanb
jdk/src/windows/classes/sun/nio/ch/PipeImpl.java
jdk/test/java/nio/channels/Pipe/PipeInterrupt.java
--- 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;
+    }
+}