1 /* 2 * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* @test 25 * @bug 6979009 26 * @summary Ensure ClosedByInterruptException is thrown when I/O operation 27 * interrupted by Thread.interrupt 28 */ 29 30 import java.io.*; 31 import java.util.Random; 32 import java.nio.ByteBuffer; 33 import java.nio.channels.*; 34 35 public class ClosedByInterrupt { 36 37 static final int K = 1024; 38 static final Random rand = new Random(); 39 40 static volatile boolean failed; 41 42 public static void main(String[] args) throws Exception { 43 File f = File.createTempFile("blah", null); 44 f.deleteOnExit(); 45 46 // create 1MB file. 47 byte[] b = new byte[K*K]; 48 rand.nextBytes(b); 49 ByteBuffer bb = ByteBuffer.wrap(b); 50 try (FileChannel fc = new FileOutputStream(f).getChannel()) { 51 while (bb.hasRemaining()) 52 fc.write(bb); 53 } 54 55 // test with 1-16 concurrent threads 56 for (int i=1; i<=16; i++) { 57 System.out.format("%d thread(s)%n", i); 58 test(f, i); 59 if (failed) 60 break; 61 } 62 63 if (failed) 64 throw new RuntimeException("Test failed"); 65 } 66 67 /** 68 * Starts "nThreads" that do I/O on the given file concurrently. Continuously 69 * interrupts one of the threads to cause the file to be closed and 70 * ClosedByInterruptException to be thrown. The other threads should "fail" with 71 * ClosedChannelException (or the more specific AsynchronousCloseException). 72 */ 73 static void test(File f, int nThreads) throws Exception { 74 try (FileChannel fc = new RandomAccessFile(f, "rwd").getChannel()) { 75 Thread[] threads = new Thread[nThreads]; 76 77 // start threads 78 for (int i=0; i<nThreads; i++) { 79 boolean interruptible = (i==0); 80 ReaderWriter task = new ReaderWriter(fc, interruptible); 81 Thread t = new Thread(task); 82 t.start(); 83 threads[i] = t; 84 } 85 86 // give time for threads to start 87 Thread.sleep(500 + rand.nextInt(1000)); 88 89 // interrupt thread until channel is closed 90 while (fc.isOpen()) { 91 threads[0].interrupt(); 92 Thread.sleep(rand.nextInt(50)); 93 } 94 95 // wait for test to finish 96 for (int i=0; i<nThreads; i++) { 97 threads[i].join(); 98 } 99 } 100 } 101 102 /** 103 * A task that continuously reads or writes to random areas of a file 104 * until the channel is closed. An "interruptible" task expects the 105 * channel to be closed by an interupt, a "non-interruptible" thread 106 * does not. 107 */ 108 static class ReaderWriter implements Runnable { 109 final FileChannel fc; 110 final boolean interruptible; 111 final boolean writer; 112 113 ReaderWriter(FileChannel fc, boolean interruptible) { 114 this.fc = fc; 115 this.interruptible = interruptible; 116 this.writer = rand.nextBoolean(); 117 } 118 119 public void run() { 120 ByteBuffer bb = ByteBuffer.allocate(K); 121 if (writer) 122 rand.nextBytes(bb.array()); 123 124 try { 125 for (;;) { 126 long position = rand.nextInt(K*K - bb.capacity()); 127 if (writer) { 128 bb.position(0).limit(bb.capacity()); 129 fc.write(bb, position); 130 } else { 131 bb.clear(); 132 fc.read(bb, position); 133 } 134 if (!interruptible) { 135 // give the interruptible thread a chance 136 try { 137 Thread.sleep(rand.nextInt(50)); 138 } catch (InterruptedException e) { 139 unexpected(e); 140 } 141 } 142 } 143 } catch (ClosedByInterruptException e) { 144 if (interruptible) { 145 if (Thread.interrupted()) { 146 expected(e + " thrown and interrupt status set"); 147 } else { 148 unexpected(e + " thrown but interrupt status not set"); 149 } 150 } else { 151 unexpected(e); 152 } 153 } catch (ClosedChannelException e) { 154 if (interruptible) { 155 unexpected(e); 156 } else { 157 expected(e); 158 } 159 } catch (Exception e) { 160 unexpected(e); 161 } 162 } 163 } 164 165 static void expected(Exception e) { 166 System.out.format("%s (expected)%n", e); 167 } 168 169 static void expected(String msg) { 170 System.out.format("%s (expected)%n", msg); 171 } 172 173 static void unexpected(Exception e) { 174 System.err.format("%s (not expected)%n", e); 175 failed = true; 176 } 177 178 static void unexpected(String msg) { 179 System.err.println(msg); 180 failed = true; 181 } 182 }