1 /* 2 * Copyright (c) 2013, 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 8012019 26 * @summary Tests interruption of threads doing position-based read methods in 27 * an attempt to provoke a deadlock between position sensitive and position 28 * insensitive methods 29 */ 30 import java.nio.ByteBuffer; 31 import java.nio.channels.*; 32 import java.nio.file.*; 33 import static java.nio.file.StandardOpenOption.*; 34 35 public class InterruptDeadlock { 36 37 /** 38 * A thread that continuously reads from a FileChannel with 39 * read(ByteBuffer,long). The thread terminates when interrupted and/or 40 * the FileChannel is closed. 41 */ 42 static class Reader extends Thread { 43 final FileChannel fc; 44 volatile Exception exception; 45 Reader(FileChannel fc)46 Reader(FileChannel fc) { 47 this.fc = fc; 48 } 49 50 @Override run()51 public void run() { 52 ByteBuffer bb = ByteBuffer.allocate(1024); 53 try { 54 long pos = 0L; 55 for (;;) { 56 bb.clear(); 57 int n = fc.read(bb, pos); 58 if (n > 0) 59 pos += n; 60 // fc.size is important here as it is position sensitive 61 if (pos > fc.size()) 62 pos = 0L; 63 } 64 } catch (ClosedChannelException x) { 65 System.out.println(x.getClass() + " (expected)"); 66 } catch (Exception unexpected) { 67 this.exception = unexpected; 68 } 69 } 70 exception()71 Exception exception() { 72 return exception; 73 } 74 startReader(FileChannel fc)75 static Reader startReader(FileChannel fc) { 76 Reader r = new Reader(fc); 77 r.start(); 78 return r; 79 } 80 } 81 82 // the number of reader threads to start 83 private static final int READER_COUNT = 4; 84 main(String[] args)85 public static void main(String[] args) throws Exception { 86 Path file = Paths.get("data.txt"); 87 try (FileChannel fc = FileChannel.open(file, CREATE, TRUNCATE_EXISTING, WRITE)) { 88 fc.position(1024L * 1024L); 89 fc.write(ByteBuffer.wrap(new byte[1])); 90 } 91 92 Reader[] readers = new Reader[READER_COUNT]; 93 94 for (int i=1; i<=20; i++) { 95 System.out.format("Iteration: %s%n", i); 96 97 try (FileChannel fc = FileChannel.open(file)) { 98 boolean failed = false; 99 100 // start reader threads 101 for (int j=0; j<READER_COUNT; j++) { 102 readers[j] = Reader.startReader(fc); 103 } 104 105 // give readers a bit of time to get started (not strictly required) 106 Thread.sleep(100); 107 108 // interrupt and wait for the readers to terminate 109 for (Reader r: readers) { 110 r.interrupt(); 111 } 112 for (Reader r: readers) { 113 try { 114 r.join(10000); 115 Exception e = r.exception(); 116 if (e != null) { 117 System.err.println("Reader thread failed with: " + e); 118 failed = true; 119 } 120 } catch (InterruptedException x) { 121 System.err.println("Reader thread did not terminte"); 122 failed = true; 123 } 124 } 125 126 // the channel should not be open at this point 127 if (fc.isOpen()) { 128 System.err.println("FileChannel was not closed"); 129 failed = true; 130 } 131 132 if (failed) 133 throw new RuntimeException("Test failed - see log for details"); 134 } 135 } 136 } 137 } 138