test/jdk/java/nio/channels/FileChannel/ClosedByInterrupt.java
changeset 47216 71c04702a3d5
parent 30046 cf2c86e1819e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/nio/channels/FileChannel/ClosedByInterrupt.java	Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2010, 2011, 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 6979009
+ * @summary Ensure ClosedByInterruptException is thrown when I/O operation
+ *     interrupted by Thread.interrupt
+ * @key randomness
+ */
+
+import java.io.*;
+import java.util.Random;
+import java.nio.ByteBuffer;
+import java.nio.channels.*;
+
+public class ClosedByInterrupt {
+
+    static final int K = 1024;
+    static final Random rand = new Random();
+
+    static volatile boolean failed;
+
+    public static void main(String[] args) throws Exception {
+        File f = File.createTempFile("blah", null);
+        f.deleteOnExit();
+
+        // create 1MB file.
+        byte[] b = new byte[K*K];
+        rand.nextBytes(b);
+        ByteBuffer bb = ByteBuffer.wrap(b);
+        try (FileChannel fc = new FileOutputStream(f).getChannel()) {
+            while (bb.hasRemaining())
+                fc.write(bb);
+        }
+
+        // test with 1-16 concurrent threads
+        for (int i=1; i<=16; i++) {
+            System.out.format("%d thread(s)%n", i);
+            test(f, i);
+            if (failed)
+                break;
+        }
+
+        if (failed)
+            throw new RuntimeException("Test failed");
+    }
+
+    /**
+     * Starts "nThreads" that do I/O on the given file concurrently. Continuously
+     * interrupts one of the threads to cause the file to be closed and
+     * ClosedByInterruptException to be thrown. The other threads should "fail" with
+     * ClosedChannelException (or the more specific AsynchronousCloseException).
+     */
+    static void test(File f, int nThreads) throws Exception {
+        try (FileChannel fc = new RandomAccessFile(f, "rwd").getChannel()) {
+            Thread[] threads = new Thread[nThreads];
+
+            // start threads
+            for (int i=0; i<nThreads; i++) {
+                boolean interruptible = (i==0);
+                ReaderWriter task = new ReaderWriter(fc, interruptible);
+                Thread t = new Thread(task);
+                t.start();
+                threads[i] = t;
+            }
+
+            // give time for threads to start
+            Thread.sleep(500 + rand.nextInt(1000));
+
+            // interrupt thread until channel is closed
+            while (fc.isOpen()) {
+                threads[0].interrupt();
+                Thread.sleep(rand.nextInt(50));
+            }
+
+            // wait for test to finish
+            for (int i=0; i<nThreads; i++) {
+                threads[i].join();
+            }
+        }
+    }
+
+    /**
+     * A task that continuously reads or writes to random areas of a file
+     * until the channel is closed. An "interruptible" task expects the
+     * channel to be closed by an interupt, a "non-interruptible" thread
+     * does not.
+     */
+    static class ReaderWriter implements Runnable {
+        final FileChannel fc;
+        final boolean interruptible;
+        final boolean writer;
+
+        ReaderWriter(FileChannel fc, boolean interruptible) {
+            this.fc = fc;
+            this.interruptible = interruptible;
+            this.writer = rand.nextBoolean();
+        }
+
+        public void run() {
+            ByteBuffer bb = ByteBuffer.allocate(K);
+            if (writer)
+                rand.nextBytes(bb.array());
+
+            try {
+                for (;;) {
+                    long position = rand.nextInt(K*K - bb.capacity());
+                    if (writer) {
+                        bb.position(0).limit(bb.capacity());
+                        fc.write(bb, position);
+                    } else {
+                        bb.clear();
+                        fc.read(bb, position);
+                    }
+                    if (!interruptible) {
+                        // give the interruptible thread a chance
+                        try {
+                            Thread.sleep(rand.nextInt(50));
+                        } catch (InterruptedException e) {
+                            unexpected(e);
+                        }
+                    }
+                }
+            } catch (ClosedByInterruptException e) {
+                if (interruptible) {
+                    if (Thread.interrupted()) {
+                        expected(e + " thrown and interrupt status set");
+                    } else {
+                        unexpected(e + " thrown but interrupt status not set");
+                    }
+                } else {
+                    unexpected(e);
+                }
+            } catch (ClosedChannelException e) {
+                if (interruptible) {
+                    unexpected(e);
+                } else {
+                    expected(e);
+                }
+            } catch (Exception e) {
+                unexpected(e);
+            }
+        }
+    }
+
+    static void expected(Exception e) {
+        System.out.format("%s (expected)%n", e);
+    }
+
+    static void expected(String msg) {
+        System.out.format("%s (expected)%n", msg);
+    }
+
+    static void unexpected(Exception e) {
+        System.err.format("%s (not expected)%n", e);
+        failed = true;
+    }
+
+    static void unexpected(String msg) {
+        System.err.println(msg);
+        failed = true;
+    }
+}