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 * @key randomness 29 */ 30 31 import java.io.*; 32 import java.util.Random; 33 import java.nio.ByteBuffer; 34 import java.nio.channels.*; 35 36 public class ClosedByInterrupt { 37 38 static final int K = 1024; 39 static final Random rand = new Random(); 40 41 static volatile boolean failed; 42 43 public static void main(String[] args) throws Exception { 44 File f = File.createTempFile("blah", null); 45 f.deleteOnExit(); 46 47 // create 1MB file. 48 byte[] b = new byte[K*K]; 49 rand.nextBytes(b); 50 ByteBuffer bb = ByteBuffer.wrap(b); 51 try (FileChannel fc = new FileOutputStream(f).getChannel()) { 52 while (bb.hasRemaining()) 53 fc.write(bb); 54 } 55 56 // test with 1-16 concurrent threads 57 for (int i=1; i<=16; i++) { 58 System.out.format("%d thread(s)%n", i); 59 test(f, i); 60 if (failed) 61 break; 62 } 63 64 if (failed) 65 throw new RuntimeException("Test failed"); 66 } 67 68 /** 69 * Starts "nThreads" that do I/O on the given file concurrently. Continuously 70 * interrupts one of the threads to cause the file to be closed and 71 * ClosedByInterruptException to be thrown. The other threads should "fail" with 72 * ClosedChannelException (or the more specific AsynchronousCloseException). 73 */ 74 static void test(File f, int nThreads) throws Exception { 75 try (FileChannel fc = new RandomAccessFile(f, "rwd").getChannel()) { 76 Thread[] threads = new Thread[nThreads]; 77 78 // start threads 79 for (int i=0; i<nThreads; i++) { 80 boolean interruptible = (i==0); 81 ReaderWriter task = new ReaderWriter(fc, interruptible); 82 Thread t = new Thread(task); 83 t.start(); 84 threads[i] = t; 85 } 86 87 // give time for threads to start 88 Thread.sleep(500 + rand.nextInt(1000)); 89 90 // interrupt thread until channel is closed 91 while (fc.isOpen()) { 92 threads[0].interrupt(); 93 Thread.sleep(rand.nextInt(50)); 94 } 95 96 // wait for test to finish 97 for (int i=0; i<nThreads; i++) { 98 threads[i].join(); 99 } 100 } 101 } 102 103 /** 104 * A task that continuously reads or writes to random areas of a file 105 * until the channel is closed. An "interruptible" task expects the 106 * channel to be closed by an interupt, a "non-interruptible" thread 107 * does not. 108 */ 109 static class ReaderWriter implements Runnable { 110 final FileChannel fc; 111 final boolean interruptible; 112 final boolean writer; 113 114 ReaderWriter(FileChannel fc, boolean interruptible) { 115 this.fc = fc; 116 this.interruptible = interruptible; 117 this.writer = rand.nextBoolean(); 118 } 119 120 public void run() { 121 ByteBuffer bb = ByteBuffer.allocate(K); 122 if (writer) 123 rand.nextBytes(bb.array()); 124 125 try { 126 for (;;) { 127 long position = rand.nextInt(K*K - bb.capacity()); 128 if (writer) { 129 bb.position(0).limit(bb.capacity()); 130 fc.write(bb, position); 131 } else { 132 bb.clear(); 133 fc.read(bb, position); 134 } 135 if (!interruptible) { 136 // give the interruptible thread a chance 137 try { 138 Thread.sleep(rand.nextInt(50)); 139 } catch (InterruptedException e) { 140 unexpected(e); 141 } 142 } 143 } 144 } catch (ClosedByInterruptException e) { 145 if (interruptible) { 146 if (Thread.interrupted()) { 147 expected(e + " thrown and interrupt status set"); 148 } else { 149 unexpected(e + " thrown but interrupt status not set"); 150 } 151 } else { 152 unexpected(e); 153 } 154 } catch (ClosedChannelException e) { 155 if (interruptible) { 156 unexpected(e); 157 } else { 158 expected(e); 159 } 160 } catch (Exception e) { 161 unexpected(e); 162 } 163 } 164 } 165 166 static void expected(Exception e) { 167 System.out.format("%s (expected)%n", e); 168 } 169 170 static void expected(String msg) { 171 System.out.format("%s (expected)%n", msg); 172 } 173 174 static void unexpected(Exception e) { 175 System.err.format("%s (not expected)%n", e); 176 failed = true; 177 } 178 179 static void unexpected(String msg) { 180 System.err.println(msg); 181 failed = true; 182 } 183 }