1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package libcore.java.nio.channels; 17 18 import junit.framework.TestCase; 19 20 import android.system.OsConstants; 21 import java.io.File; 22 import java.io.FileInputStream; 23 import java.io.FileOutputStream; 24 import java.io.InterruptedIOException; 25 import java.io.IOException; 26 import java.nio.ByteBuffer; 27 import java.nio.channels.AsynchronousCloseException; 28 import java.nio.channels.ClosedByInterruptException; 29 import java.nio.channels.ClosedChannelException; 30 import java.nio.channels.FileChannel; 31 import libcore.io.Libcore; 32 33 import static libcore.io.IoUtils.closeQuietly; 34 35 /** 36 * A test for file interrupt behavior. Because forcing a real file to block on read or write is 37 * difficult this test uses Unix FIFO / Named Pipes. FIFOs appear to Java as files but the test 38 * has more control over the available data. Reader will block until the other end writes, and 39 * writers can also be made to block. 40 * 41 * <p>Using FIFOs has a few drawbacks: 42 * <ol> 43 * <li>FIFOs are not supported from Java or the command-line on Android, so this test includes 44 * native code to create the FIFO. 45 * <li>FIFOs will not open() until there is both a reader and a writer of the FIFO; each test must 46 * always attach both ends or experience a blocked test. 47 * <li>FIFOs are not supported on some file systems. e.g. VFAT, so the test has to be particular 48 * about the temporary directory it uses to hold the FIFO. 49 * <li>Writes to FIFOs are buffered by the OS which makes blocking behavior more difficult to 50 * induce. See {@link ChannelWriter} and {@link StreamWriter}. 51 * </ol> 52 */ 53 public class FileIOInterruptTest extends TestCase { 54 55 private static File VOGAR_DEVICE_TEMP_DIR = new File("/data/data/file_io_interrupt_test"); 56 57 private File fifoFile; 58 59 @Override 60 public void setUp() throws Exception { 61 super.setUp(); 62 63 // This test relies on a FIFO file. The file system must support FIFOs, so we check the path. 64 String tmpDirName = System.getProperty("java.io.tmpdir"); 65 File tmpDir; 66 if (tmpDirName.startsWith("/sdcard")) { 67 // Vogar execution on device runs in /sdcard. Unfortunately the file system used does not 68 // support FIFOs so the test must use one that is more likely to work. 69 if (!VOGAR_DEVICE_TEMP_DIR.exists()) { 70 assertTrue(VOGAR_DEVICE_TEMP_DIR.mkdir()); 71 } 72 VOGAR_DEVICE_TEMP_DIR.deleteOnExit(); 73 tmpDir = VOGAR_DEVICE_TEMP_DIR; 74 } else { 75 tmpDir = new File(tmpDirName); 76 } 77 fifoFile = new File(tmpDir, "fifo_file.tmp"); 78 if (fifoFile.exists()) { 79 fifoFile.delete(); 80 } 81 fifoFile.deleteOnExit(); 82 83 // Create the fifo. This will throw an exception if the file system does not support it. 84 Libcore.os.mkfifo(fifoFile.getAbsolutePath(), OsConstants.S_IRWXU); 85 } 86 87 @Override 88 public void tearDown() throws Exception { 89 super.tearDown(); 90 fifoFile.delete(); 91 VOGAR_DEVICE_TEMP_DIR.delete(); 92 93 // Clear the interrupted state, if set. 94 Thread.interrupted(); 95 } 96 97 public void testStreamRead_exceptionWhenAlreadyClosed() throws Exception { 98 FifoWriter fifoWriter = new FifoWriter(fifoFile); 99 fifoWriter.start(); 100 101 FileInputStream fis = new FileInputStream(fifoFile); 102 fis.close(); 103 104 byte[] buffer = new byte[10]; 105 try { 106 fis.read(buffer); 107 fail(); 108 } catch (IOException expected) { 109 assertSame(IOException.class, expected.getClass()); 110 } 111 112 fifoWriter.tidyUp(); 113 } 114 115 // This test fails on the RI: close() does not wake up a blocking FileInputStream.read() call. 116 public void testStreamRead_exceptionOnCloseWhenBlocked() throws Exception { 117 FifoWriter fifoWriter = new FifoWriter(fifoFile); 118 fifoWriter.start(); 119 120 FileInputStream fis = new FileInputStream(fifoFile); 121 StreamReader streamReader = new StreamReader(fis); 122 Thread streamReaderThread = createAndStartThread("StreamReader", streamReader); 123 124 // Delay until we can be fairly sure the reader thread is blocking. 125 streamReader.waitForThreadToBlock(); 126 127 // Now close the OutputStream to see what happens. 128 fis.close(); 129 130 // Test for expected behavior in the reader thread. 131 waitToDie(streamReaderThread); 132 assertSame(InterruptedIOException.class, streamReader.ioe.getClass()); 133 assertFalse(streamReader.wasInterrupted); 134 135 // Tidy up the writer thread. 136 fifoWriter.tidyUp(); 137 } 138 139 public void testStreamWrite_exceptionWhenAlreadyClosed() throws Exception { 140 FifoReader fifoReader = new FifoReader(fifoFile); 141 fifoReader.start(); 142 143 FileOutputStream fos = new FileOutputStream(fifoFile); 144 byte[] buffer = new byte[10]; 145 fos.close(); 146 147 try { 148 fos.write(buffer); 149 fail(); 150 } catch (IOException expected) { 151 assertSame(IOException.class, expected.getClass()); 152 } 153 154 fifoReader.tidyUp(); 155 } 156 157 // This test fails on the RI: close() does not wake up a blocking FileInputStream.write() call. 158 public void testStreamWrite_exceptionOnCloseWhenBlocked() throws Exception { 159 FifoReader fifoReader = new FifoReader(fifoFile); 160 fifoReader.start(); 161 162 FileOutputStream fos = new FileOutputStream(fifoFile); 163 StreamWriter streamWriter = new StreamWriter(fos); 164 Thread streamWriterThread = createAndStartThread("StreamWriter", streamWriter); 165 166 // Delay until we can be fairly sure the writer thread is blocking. 167 streamWriter.waitForThreadToBlock(); 168 169 // Now close the OutputStream to see what happens. 170 fos.close(); 171 172 // Test for expected behavior in the writer thread. 173 waitToDie(streamWriterThread); 174 assertSame(InterruptedIOException.class, streamWriter.ioe.getClass()); 175 assertFalse(streamWriter.wasInterrupted); 176 177 // Tidy up the reader thread. 178 fifoReader.tidyUp(); 179 } 180 181 public void testChannelRead_exceptionWhenAlreadyClosed() throws Exception { 182 testChannelRead_exceptionWhenAlreadyClosed(ChannelReader.Method.READ); 183 } 184 185 public void testChannelReadV_exceptionWhenAlreadyClosed() throws Exception { 186 testChannelRead_exceptionWhenAlreadyClosed(ChannelReader.Method.READV); 187 } 188 189 private void testChannelRead_exceptionWhenAlreadyClosed(ChannelReader.Method method) 190 throws Exception { 191 FifoWriter fifoWriter = new FifoWriter(fifoFile); 192 fifoWriter.start(); 193 FileInputStream fis = new FileInputStream(fifoFile); 194 FileChannel fileInputChannel = fis.getChannel(); 195 fileInputChannel.close(); 196 197 ByteBuffer buffer = ByteBuffer.allocateDirect(10); 198 try { 199 if (method == ChannelReader.Method.READ) { 200 fileInputChannel.read(buffer); 201 } else { 202 ByteBuffer buffer2 = ByteBuffer.allocateDirect(10); 203 fileInputChannel.read(new ByteBuffer[] { buffer, buffer2}); 204 } 205 fail(); 206 } catch (IOException expected) { 207 assertSame(ClosedChannelException.class, expected.getClass()); 208 } 209 210 fifoWriter.tidyUp(); 211 } 212 213 public void testChannelRead_exceptionWhenAlreadyInterrupted() throws Exception { 214 testChannelRead_exceptionWhenAlreadyInterrupted(ChannelReader.Method.READ); 215 } 216 217 public void testChannelReadV_exceptionWhenAlreadyInterrupted() throws Exception { 218 testChannelRead_exceptionWhenAlreadyInterrupted(ChannelReader.Method.READV); 219 } 220 221 private void testChannelRead_exceptionWhenAlreadyInterrupted(ChannelReader.Method method) 222 throws Exception { 223 FifoWriter fifoWriter = new FifoWriter(fifoFile); 224 fifoWriter.start(); 225 FileInputStream fis = new FileInputStream(fifoFile); 226 FileChannel fileInputChannel = fis.getChannel(); 227 228 Thread.currentThread().interrupt(); 229 230 ByteBuffer buffer = ByteBuffer.allocateDirect(10); 231 try { 232 if (method == ChannelReader.Method.READ) { 233 fileInputChannel.read(buffer); 234 } else { 235 ByteBuffer buffer2 = ByteBuffer.allocateDirect(10); 236 fileInputChannel.read(new ByteBuffer[] { buffer, buffer2}); 237 } 238 fail(); 239 } catch (IOException expected) { 240 assertSame(ClosedByInterruptException.class, expected.getClass()); 241 } 242 243 // Check but also clear the interrupted status, so we can wait for the FifoWriter thread in 244 // tidyUp(). 245 assertTrue(Thread.interrupted()); 246 247 fifoWriter.tidyUp(); 248 } 249 250 public void testChannelRead_exceptionOnCloseWhenBlocked() throws Exception { 251 testChannelRead_exceptionOnCloseWhenBlocked(ChannelReader.Method.READ); 252 } 253 254 public void testChannelReadV_exceptionOnCloseWhenBlocked() throws Exception { 255 testChannelRead_exceptionOnCloseWhenBlocked(ChannelReader.Method.READV); 256 } 257 258 private void testChannelRead_exceptionOnCloseWhenBlocked(ChannelReader.Method method) 259 throws Exception { 260 FifoWriter fifoWriter = new FifoWriter(fifoFile); 261 fifoWriter.start(); 262 FileInputStream fis = new FileInputStream(fifoFile); 263 FileChannel fileInputChannel = fis.getChannel(); 264 265 ChannelReader channelReader = new ChannelReader(fileInputChannel, method); 266 Thread channelReaderThread = createAndStartThread("ChannelReader", channelReader); 267 268 // Delay until we can be fairly sure the reader thread is blocking. 269 channelReader.waitForThreadToBlock(); 270 271 // Now close the FileChannel to see what happens. 272 fileInputChannel.close(); 273 274 // Test for expected behavior in the reader thread. 275 waitToDie(channelReaderThread); 276 assertSame(AsynchronousCloseException.class, channelReader.ioe.getClass()); 277 assertFalse(channelReader.wasInterrupted); 278 279 // Tidy up the writer thread. 280 fifoWriter.tidyUp(); 281 } 282 283 public void testChannelRead_exceptionOnInterrupt() throws Exception { 284 testChannelRead_exceptionOnInterrupt(ChannelReader.Method.READ); 285 } 286 287 public void testChannelReadV_exceptionOnInterrupt() throws Exception { 288 testChannelRead_exceptionOnInterrupt(ChannelReader.Method.READV); 289 } 290 291 private void testChannelRead_exceptionOnInterrupt(ChannelReader.Method method) throws Exception { 292 FifoWriter fifoWriter = new FifoWriter(fifoFile); 293 fifoWriter.start(); 294 FileChannel fileChannel = new FileInputStream(fifoFile).getChannel(); 295 296 ChannelReader channelReader = new ChannelReader(fileChannel, method); 297 Thread channelReaderThread = createAndStartThread("ChannelReader", channelReader); 298 299 // Delay until we can be fairly sure the reader thread is blocking. 300 channelReader.waitForThreadToBlock(); 301 302 // Now interrupt the reader thread to see what happens. 303 channelReaderThread.interrupt(); 304 305 // Test for expected behavior in the reader thread. 306 waitToDie(channelReaderThread); 307 assertSame(ClosedByInterruptException.class, channelReader.ioe.getClass()); 308 assertTrue(channelReader.wasInterrupted); 309 310 // Tidy up the writer thread. 311 fifoWriter.tidyUp(); 312 } 313 314 public void testChannelWrite_exceptionWhenAlreadyClosed() throws Exception { 315 testChannelWrite_exceptionWhenAlreadyClosed(ChannelWriter.Method.WRITE); 316 } 317 318 public void testChannelWriteV_exceptionWhenAlreadyClosed() throws Exception { 319 testChannelWrite_exceptionWhenAlreadyClosed(ChannelWriter.Method.WRITEV); 320 } 321 322 private void testChannelWrite_exceptionWhenAlreadyClosed(ChannelWriter.Method method) 323 throws Exception { 324 FifoReader fifoReader = new FifoReader(fifoFile); 325 fifoReader.start(); 326 FileChannel fileOutputChannel = new FileOutputStream(fifoFile).getChannel(); 327 fileOutputChannel.close(); 328 329 ByteBuffer buffer = ByteBuffer.allocateDirect(10); 330 try { 331 if (method == ChannelWriter.Method.WRITE) { 332 fileOutputChannel.write(buffer); 333 } else { 334 ByteBuffer buffer2 = ByteBuffer.allocateDirect(10); 335 fileOutputChannel.write(new ByteBuffer[] { buffer, buffer2 }); 336 } 337 fail(); 338 } catch (IOException expected) { 339 assertSame(ClosedChannelException.class, expected.getClass()); 340 } 341 342 fifoReader.tidyUp(); 343 } 344 345 public void testChannelWrite_exceptionWhenAlreadyInterrupted() throws Exception { 346 testChannelWrite_exceptionWhenAlreadyInterrupted(ChannelWriter.Method.WRITE); 347 } 348 349 public void testChannelWriteV_exceptionWhenAlreadyInterrupted() throws Exception { 350 testChannelWrite_exceptionWhenAlreadyInterrupted(ChannelWriter.Method.WRITEV); 351 } 352 353 private void testChannelWrite_exceptionWhenAlreadyInterrupted(ChannelWriter.Method method) 354 throws Exception { 355 FifoReader fifoReader = new FifoReader(fifoFile); 356 fifoReader.start(); 357 FileOutputStream fos = new FileOutputStream(fifoFile); 358 FileChannel fileInputChannel = fos.getChannel(); 359 360 Thread.currentThread().interrupt(); 361 362 ByteBuffer buffer = ByteBuffer.allocateDirect(10); 363 try { 364 if (method == ChannelWriter.Method.WRITE) { 365 fileInputChannel.write(buffer); 366 } else { 367 ByteBuffer buffer2 = ByteBuffer.allocateDirect(10); 368 fileInputChannel.write(new ByteBuffer[] { buffer, buffer2 }); 369 } 370 fail(); 371 } catch (IOException expected) { 372 assertSame(ClosedByInterruptException.class, expected.getClass()); 373 } 374 375 // Check but also clear the interrupted status, so we can wait for the FifoReader thread in 376 // tidyUp(). 377 assertTrue(Thread.interrupted()); 378 379 fifoReader.tidyUp(); 380 } 381 382 public void testChannelWrite_exceptionOnCloseWhenBlocked() throws Exception { 383 testChannelWrite_exceptionOnCloseWhenBlocked(ChannelWriter.Method.WRITE); 384 } 385 386 public void testChannelWriteV_exceptionOnCloseWhenBlocked() throws Exception { 387 testChannelWrite_exceptionOnCloseWhenBlocked(ChannelWriter.Method.WRITEV); 388 } 389 390 private void testChannelWrite_exceptionOnCloseWhenBlocked(ChannelWriter.Method method) 391 throws Exception { 392 FifoReader fifoReader = new FifoReader(fifoFile); 393 fifoReader.start(); 394 FileChannel fileOutputChannel = new FileOutputStream(fifoFile).getChannel(); 395 396 ChannelWriter channelWriter = new ChannelWriter(fileOutputChannel, method); 397 Thread channelWriterThread = createAndStartThread("ChannelWriter", channelWriter); 398 399 // Delay until we can be fairly sure the writer thread is blocking. 400 channelWriter.waitForThreadToBlock(); 401 402 // Now close the channel to see what happens. 403 fileOutputChannel.close(); 404 405 // Test for expected behavior in the writer thread. 406 waitToDie(channelWriterThread); 407 // // The RI throws ChannelClosedException. AsynchronousCloseException is more correct according to 408 // // the docs. 409 // 410 // Lies. RI throws AsynchronousCloseException only if NO data was written before interrupt. 411 // I altered the ChannelWriter to write exactly 32k bytes and this triggers this behavior. 412 // the AsynchronousCloseException. If some of data is written, the #write will return the number 413 // of bytes written, and then the FOLLOWING #write will throw ChannelClosedException because 414 // file has been closed. Android is actually doing a wrong thing by always throwing the 415 // AsynchronousCloseException. Client application have no idea that SOME data 416 // was written in this case. 417 assertSame(AsynchronousCloseException.class, channelWriter.ioe.getClass()); 418 assertFalse(channelWriter.wasInterrupted); 419 420 // Tidy up the writer thread. 421 fifoReader.tidyUp(); 422 } 423 424 public void testChannelWrite_exceptionOnInterrupt() throws Exception { 425 testChannelWrite_exceptionOnInterrupt(ChannelWriter.Method.WRITE); 426 } 427 428 public void testChannelWriteV_exceptionOnInterrupt() throws Exception { 429 testChannelWrite_exceptionOnInterrupt(ChannelWriter.Method.WRITEV); 430 } 431 432 private void testChannelWrite_exceptionOnInterrupt(ChannelWriter.Method method) throws Exception { 433 FifoReader fifoReader = new FifoReader(fifoFile); 434 fifoReader.start(); 435 436 FileChannel fileChannel = new FileOutputStream(fifoFile).getChannel(); 437 ChannelWriter channelWriter = new ChannelWriter(fileChannel, method); 438 Thread channelWriterThread = createAndStartThread("ChannelWriter", channelWriter); 439 440 // Delay until we can be fairly sure the writer thread is blocking. 441 channelWriter.waitForThreadToBlock(); 442 443 // Now interrupt the writer thread to see what happens. 444 channelWriterThread.interrupt(); 445 446 // Test for expected behavior in the writer thread. 447 waitToDie(channelWriterThread); 448 assertSame(ClosedByInterruptException.class, channelWriter.ioe.getClass()); 449 assertTrue(channelWriter.wasInterrupted); 450 451 // Tidy up the reader thread. 452 fifoReader.tidyUp(); 453 } 454 455 private static class StreamReader implements Runnable { 456 457 private final FileInputStream inputStream; 458 volatile boolean started; 459 volatile IOException ioe; 460 volatile boolean wasInterrupted; 461 462 StreamReader(FileInputStream inputStream) { 463 this.inputStream = inputStream; 464 } 465 466 @Override 467 public void run() { 468 byte[] buffer = new byte[10]; 469 try { 470 started = true; 471 int bytesRead = inputStream.read(buffer); 472 fail("This isn't supposed to happen: read() returned: " + bytesRead); 473 } catch (IOException e) { 474 this.ioe = e; 475 } 476 wasInterrupted = Thread.interrupted(); 477 } 478 479 public void waitForThreadToBlock() { 480 for (int i = 0; i < 10 && !started; i++) { 481 delay(100); 482 } 483 assertTrue(started); 484 // Just give it some more time to start blocking. 485 delay(100); 486 } 487 } 488 489 private static class StreamWriter implements Runnable { 490 491 private final FileOutputStream outputStream; 492 volatile int bytesWritten; 493 volatile IOException ioe; 494 volatile boolean wasInterrupted; 495 496 StreamWriter(FileOutputStream outputStream) { 497 this.outputStream = outputStream; 498 } 499 500 @Override 501 public void run() { 502 // Writes to FIFOs are buffered. We try to fill the buffer and induce blocking (the 503 // buffer is typically 64k). 504 byte[] buffer = new byte[10000]; 505 while (true) { 506 try { 507 outputStream.write(buffer); 508 bytesWritten += buffer.length; 509 } catch (IOException e) { 510 this.ioe = e; 511 break; 512 } 513 wasInterrupted = Thread.interrupted(); 514 } 515 } 516 517 public void waitForThreadToBlock() { 518 int lastCount = bytesWritten; 519 for (int i = 0; i < 10; i++) { 520 delay(500); 521 int newBytesWritten = bytesWritten; 522 if (newBytesWritten > 0 && lastCount == newBytesWritten) { 523 // The thread is probably blocking. 524 return; 525 } 526 lastCount = bytesWritten; 527 } 528 fail("Writer never started blocking. Bytes written: " + bytesWritten); 529 } 530 } 531 532 private static class ChannelReader implements Runnable { 533 enum Method { 534 READ, 535 READV, 536 } 537 538 private final FileChannel channel; 539 private final Method method; 540 volatile boolean started; 541 volatile IOException ioe; 542 volatile boolean wasInterrupted; 543 544 ChannelReader(FileChannel channel, Method method) { 545 this.channel = channel; 546 this.method = method; 547 } 548 549 @Override 550 public void run() { 551 ByteBuffer buffer = ByteBuffer.allocateDirect(10); 552 try { 553 started = true; 554 if (method == Method.READ) { 555 channel.read(buffer); 556 } else { 557 ByteBuffer buffer2 = ByteBuffer.allocateDirect(10); 558 channel.read(new ByteBuffer[] { buffer, buffer2 }); 559 } 560 fail("All tests should block until an exception"); 561 } catch (IOException e) { 562 this.ioe = e; 563 } 564 wasInterrupted = Thread.interrupted(); 565 } 566 567 public void waitForThreadToBlock() { 568 for (int i = 0; i < 10 && !started; i++) { 569 delay(100); 570 } 571 assertTrue(started); 572 // Just give it some more time to start blocking. 573 delay(100); 574 } 575 } 576 577 private static class ChannelWriter implements Runnable { 578 enum Method { 579 WRITE, 580 WRITEV, 581 } 582 583 private final FileChannel channel; 584 private final Method method; 585 volatile int bytesWritten; 586 volatile IOException ioe; 587 volatile boolean wasInterrupted; 588 589 ChannelWriter(FileChannel channel, Method method) { 590 this.channel = channel; 591 this.method = method; 592 } 593 594 @Override 595 public void run() { 596 ByteBuffer buffer1 = ByteBuffer.allocateDirect(32000); 597 ByteBuffer buffer2 = ByteBuffer.allocateDirect(32000); 598 // Writes to FIFOs are buffered. We try to fill the buffer and induce blocking (the 599 // buffer is typically 64k). 600 while (true) { 601 // Make the buffers look non-empty. 602 buffer1.position(0).limit(buffer1.capacity()); 603 buffer2.position(0).limit(buffer2.capacity()); 604 try { 605 if (method == Method.WRITE) { 606 bytesWritten += channel.write(buffer1); 607 } else { 608 bytesWritten += channel.write(new ByteBuffer[]{ buffer1, buffer2 }); 609 } 610 } catch (IOException e) { 611 this.ioe = e; 612 break; 613 } 614 } 615 wasInterrupted = Thread.interrupted(); 616 } 617 618 public void waitForThreadToBlock() { 619 int lastCount = bytesWritten; 620 for (int i = 0; i < 10; i++) { 621 delay(500); 622 int newBytesWritten = bytesWritten; 623 if (newBytesWritten > 0 && lastCount == newBytesWritten) { 624 // The thread is probably blocking. 625 return; 626 } 627 lastCount = bytesWritten; 628 } 629 fail("Writer never started blocking. Bytes written: " + bytesWritten); 630 } 631 } 632 633 /** 634 * Opens a FIFO for writing. Exists to unblock the other end of the FIFO. 635 */ 636 private static class FifoWriter extends Thread { 637 638 private final File file; 639 private FileOutputStream fos; 640 641 public FifoWriter(File file) { 642 super("FifoWriter"); 643 this.file = file; 644 } 645 646 @Override 647 public void run() { 648 try { 649 fos = new FileOutputStream(file); 650 } catch (IOException ignored) { 651 } 652 } 653 654 public void tidyUp() { 655 FileIOInterruptTest.waitToDie(this); 656 closeQuietly(fos); 657 } 658 } 659 660 /** 661 * Opens a FIFO for reading. Exists to unblock the other end of the FIFO. 662 */ 663 private static class FifoReader extends Thread { 664 665 private final File file; 666 private FileInputStream fis; 667 668 public FifoReader(File file) { 669 super("FifoReader"); 670 this.file = file; 671 } 672 673 @Override 674 public void run() { 675 try { 676 fis = new FileInputStream(file); 677 } catch (IOException ignored) { 678 } 679 } 680 681 public void tidyUp() { 682 FileIOInterruptTest.waitToDie(this); 683 closeQuietly(fis); 684 } 685 } 686 687 private static Thread createAndStartThread(String name, Runnable runnable) { 688 Thread t = new Thread(runnable, name); 689 t.setDaemon(true); 690 t.start(); 691 return t; 692 } 693 694 private static void waitToDie(Thread thread) { 695 // Protect against this thread already being interrupted, which would prevent the test waiting 696 // for the requested time. 697 assertFalse(Thread.currentThread().isInterrupted()); 698 try { 699 thread.join(5000); 700 } catch (InterruptedException ignored) { 701 } 702 703 if (thread.isAlive()) { 704 fail("Thread \"" + thread.getName() + "\" did not exit."); 705 } 706 } 707 708 private static void delay(int millis) { 709 // Protect against this thread being interrupted, which would prevent us waiting. 710 assertFalse(Thread.currentThread().isInterrupted()); 711 try { 712 Thread.sleep(millis); 713 } catch (InterruptedException ignored) { 714 } 715 } 716 717 } 718