/* * Copyright (c) 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 7105952 6322678 7082769 * @summary Improve finalisation for FileInputStream/FileOutputStream/RandomAccessFile * @run main/othervm Sharing */ import java.io.*; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.util.concurrent.CountDownLatch; public class Sharing { final static int numFiles = 10; volatile static boolean fail; public static void main(String[] args) throws Exception { TestFinalizer(); TestMultipleFD(); TestIsValid(); MultiThreadedFD(); TestCloseAll(); } /** * Finalizer shouldn't discard a file descriptor until all streams have * finished with it. */ private static void TestFinalizer() throws Exception { FileDescriptor fd = null; File tempFile = new File("TestFinalizer1.txt"); tempFile.deleteOnExit(); try (Writer writer = new FileWriter(tempFile)) { for (int i=0; i<5; i++) { writer.write("test file content test file content"); } } FileInputStream fis1 = new FileInputStream(tempFile); fd = fis1.getFD(); // Create a new FIS based on the existing FD (so the two FIS's share the same native fd) try (FileInputStream fis2 = new FileInputStream(fd)) { // allow fis1 to be gc'ed fis1 = null; int ret = 0; while(ret >= 0) { // encourage gc System.gc(); // read from fis2 - when fis1 is gc'ed and finalizer is run, read will fail System.out.print("."); ret = fis2.read(); } } // variation of above. Use RandomAccessFile to obtain a filedescriptor File testFinalizerFile = new File("TestFinalizer"); RandomAccessFile raf = new RandomAccessFile(testFinalizerFile, "rw"); raf.writeBytes("test file content test file content"); raf.seek(0L); fd = raf.getFD(); try (FileInputStream fis3 = new FileInputStream(fd)) { // allow raf to be gc'ed raf = null; int ret = 0; while (ret >= 0) { // encourage gc System.gc(); /* * read from fis3 - when raf is gc'ed and finalizer is run, * fd should still be valid. */ System.out.print("."); ret = fis3.read(); } } finally { testFinalizerFile.delete(); } } /** * Exercise FileDispatcher close()/preClose() */ private static void TestMultipleFD() throws Exception { RandomAccessFile raf = null; FileOutputStream fos = null; FileInputStream fis = null; FileChannel fc = null; FileLock fileLock = null; File test1 = new File("test1"); try { raf = new RandomAccessFile(test1, "rw"); fos = new FileOutputStream(raf.getFD()); fis = new FileInputStream(raf.getFD()); fc = raf.getChannel(); fileLock = fc.lock(); raf.setLength(0L); fos.flush(); fos.write("TEST".getBytes()); } finally { if (fileLock != null) fileLock.release(); if (fis != null) fis.close(); if (fos != null) fos.close(); if (raf != null) raf.close(); test1.delete(); } /* * Close out in different order to ensure FD is not * closed out too early */ File test2 = new File("test2"); try { raf = new RandomAccessFile(test2, "rw"); fos = new FileOutputStream(raf.getFD()); fis = new FileInputStream(raf.getFD()); fc = raf.getChannel(); fileLock = fc.lock(); raf.setLength(0L); fos.flush(); fos.write("TEST".getBytes()); } finally { if (fileLock != null) fileLock.release(); if (raf != null) raf.close(); if (fos != null) fos.close(); if (fis != null) fis.close(); test2.delete(); } // one more time, fos first this time File test3 = new File("test3"); try { raf = new RandomAccessFile(test3, "rw"); fos = new FileOutputStream(raf.getFD()); fis = new FileInputStream(raf.getFD()); fc = raf.getChannel(); fileLock = fc.lock(); raf.setLength(0L); fos.flush(); fos.write("TEST".getBytes()); } finally { if (fileLock != null) fileLock.release(); if (fos != null) fos.close(); if (raf != null) raf.close(); if (fis != null) fis.close(); test3.delete(); } } /** * Similar to TestMultipleFD() but this time we * just get and use FileDescriptor.valid() for testing. */ private static void TestIsValid() throws Exception { FileDescriptor fd = null; RandomAccessFile raf = null; FileOutputStream fos = null; FileInputStream fis = null; FileChannel fc = null; File test1 = new File("test1"); try { raf = new RandomAccessFile(test1, "rw"); fd = raf.getFD(); fos = new FileOutputStream(fd); fis = new FileInputStream(fd); } finally { try { if (fis != null) fis.close(); if (fd.valid()) { throw new RuntimeException("[FIS close()] FileDescriptor shouldn't be valid"); } if (fos != null) fos.close(); if (raf != null) raf.close(); } finally { test1.delete(); } } /* * Close out in different order to ensure FD is * closed correctly. */ File test2 = new File("test2"); try { raf = new RandomAccessFile(test2, "rw"); fd = raf.getFD(); fos = new FileOutputStream(fd); fis = new FileInputStream(fd); } finally { try { if (raf != null) raf.close(); if (fd.valid()) { throw new RuntimeException("[RAF close()] FileDescriptor shouldn't be valid"); } if (fos != null) fos.close(); if (fis != null) fis.close(); } finally { test2.delete(); } } // one more time, fos first this time File test3 = new File("test3"); try { raf = new RandomAccessFile(test3, "rw"); fd = raf.getFD(); fos = new FileOutputStream(fd); fis = new FileInputStream(fd); } finally { try { if (fos != null) fos.close(); if (fd.valid()) { throw new RuntimeException("[FOS close()] FileDescriptor shouldn't be valid"); } if (raf != null) raf.close(); if (fis != null) fis.close(); } finally { test3.delete(); } } } /** * Test concurrent access to the same FileDescriptor */ private static void MultiThreadedFD() throws Exception { RandomAccessFile raf = null; FileDescriptor fd = null; int numThreads = 2; CountDownLatch done = new CountDownLatch(numThreads); OpenClose[] fileOpenClose = new OpenClose[numThreads]; File MultipleThreadedFD = new File("MultipleThreadedFD"); try { raf = new RandomAccessFile(MultipleThreadedFD, "rw"); fd = raf.getFD(); for(int count=0;count