Path: blob/master/test/jdk/java/io/FileDescriptor/Sharing.java
41149 views
/*1* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 7105952 6322678 708276926* @summary Improve finalisation for FileInputStream/FileOutputStream/RandomAccessFile27* @run main/othervm Sharing28*/2930import java.io.*;31import java.nio.channels.FileChannel;32import java.nio.channels.FileLock;33import java.util.concurrent.CountDownLatch;3435public class Sharing {3637static final int numFiles = 10;38static volatile boolean fail;3940public static void main(String[] args) throws Exception {41TestFinalizer();42TestMultipleFD();43TestIsValid();44MultiThreadedFD();45TestCloseAll();46}4748/**49* Finalizer shouldn't discard a file descriptor until all streams have50* finished with it.51*/52private static void TestFinalizer() throws Exception {53FileDescriptor fd = null;54File tempFile = new File("TestFinalizer1.txt");55tempFile.deleteOnExit();56try (Writer writer = new FileWriter(tempFile)) {57for (int i=0; i<5; i++) {58writer.write("test file content test file content");59}60}6162FileInputStream fis1 = new FileInputStream(tempFile);63fd = fis1.getFD();64// Create a new FIS based on the existing FD (so the two FIS's share the same native fd)65try (FileInputStream fis2 = new FileInputStream(fd)) {66// allow fis1 to be gc'ed67fis1 = null;68int ret = 0;69while(ret >= 0) {70// encourage gc71System.gc();72// read from fis2 - when fis1 is gc'ed and finalizer is run, read will fail73System.out.print(".");74ret = fis2.read();75}76}7778// variation of above. Use RandomAccessFile to obtain a filedescriptor79File testFinalizerFile = new File("TestFinalizer");80RandomAccessFile raf = new RandomAccessFile(testFinalizerFile, "rw");81raf.writeBytes("test file content test file content");82raf.seek(0L);83fd = raf.getFD();84try (FileInputStream fis3 = new FileInputStream(fd)) {85// allow raf to be gc'ed86raf = null;87int ret = 0;88while (ret >= 0) {89// encourage gc90System.gc();91/*92* read from fis3 - when raf is gc'ed and finalizer is run,93* fd should still be valid.94*/95System.out.print(".");96ret = fis3.read();97}98} finally {99testFinalizerFile.delete();100}101}102103/**104* Exercise FileDispatcher close()/preClose()105*/106private static void TestMultipleFD() throws Exception {107RandomAccessFile raf = null;108FileOutputStream fos = null;109FileInputStream fis = null;110FileChannel fc = null;111FileLock fileLock = null;112113File test1 = new File("test1");114try {115raf = new RandomAccessFile(test1, "rw");116fos = new FileOutputStream(raf.getFD());117fis = new FileInputStream(raf.getFD());118fc = raf.getChannel();119fileLock = fc.lock();120raf.setLength(0L);121fos.flush();122fos.write("TEST".getBytes());123} finally {124if (fileLock != null) fileLock.release();125if (fis != null) fis.close();126if (fos != null) fos.close();127if (raf != null) raf.close();128test1.delete();129}130131/*132* Close out in different order to ensure FD is not133* closed out too early134*/135File test2 = new File("test2");136try {137raf = new RandomAccessFile(test2, "rw");138fos = new FileOutputStream(raf.getFD());139fis = new FileInputStream(raf.getFD());140fc = raf.getChannel();141fileLock = fc.lock();142raf.setLength(0L);143fos.flush();144fos.write("TEST".getBytes());145} finally {146if (fileLock != null) fileLock.release();147if (raf != null) raf.close();148if (fos != null) fos.close();149if (fis != null) fis.close();150test2.delete();151}152153// one more time, fos first this time154File test3 = new File("test3");155try {156raf = new RandomAccessFile(test3, "rw");157fos = new FileOutputStream(raf.getFD());158fis = new FileInputStream(raf.getFD());159fc = raf.getChannel();160fileLock = fc.lock();161raf.setLength(0L);162fos.flush();163fos.write("TEST".getBytes());164} finally {165if (fileLock != null) fileLock.release();166if (fos != null) fos.close();167if (raf != null) raf.close();168if (fis != null) fis.close();169test3.delete();170}171}172173/**174* Similar to TestMultipleFD() but this time we175* just get and use FileDescriptor.valid() for testing.176*/177private static void TestIsValid() throws Exception {178FileDescriptor fd = null;179RandomAccessFile raf = null;180FileOutputStream fos = null;181FileInputStream fis = null;182FileChannel fc = null;183184File test1 = new File("test1");185try {186raf = new RandomAccessFile(test1, "rw");187fd = raf.getFD();188fos = new FileOutputStream(fd);189fis = new FileInputStream(fd);190} finally {191try {192if (fis != null) fis.close();193if (fd.valid()) {194throw new RuntimeException("[FIS close()] FileDescriptor shouldn't be valid");195}196if (fos != null) fos.close();197if (raf != null) raf.close();198} finally {199test1.delete();200}201}202203/*204* Close out in different order to ensure FD is205* closed correctly.206*/207File test2 = new File("test2");208try {209raf = new RandomAccessFile(test2, "rw");210fd = raf.getFD();211fos = new FileOutputStream(fd);212fis = new FileInputStream(fd);213} finally {214try {215if (raf != null) raf.close();216if (fd.valid()) {217throw new RuntimeException("[RAF close()] FileDescriptor shouldn't be valid");218}219if (fos != null) fos.close();220if (fis != null) fis.close();221} finally {222test2.delete();223}224}225226// one more time, fos first this time227File test3 = new File("test3");228try {229raf = new RandomAccessFile(test3, "rw");230fd = raf.getFD();231fos = new FileOutputStream(fd);232fis = new FileInputStream(fd);233} finally {234try {235if (fos != null) fos.close();236if (fd.valid()) {237throw new RuntimeException("[FOS close()] FileDescriptor shouldn't be valid");238}239if (raf != null) raf.close();240if (fis != null) fis.close();241} finally {242test3.delete();243}244}245}246247/**248* Test concurrent access to the same FileDescriptor249*/250private static void MultiThreadedFD() throws Exception {251RandomAccessFile raf = null;252FileDescriptor fd = null;253int numThreads = 2;254CountDownLatch done = new CountDownLatch(numThreads);255OpenClose[] fileOpenClose = new OpenClose[numThreads];256File MultipleThreadedFD = new File("MultipleThreadedFD");257try {258raf = new RandomAccessFile(MultipleThreadedFD, "rw");259fd = raf.getFD();260for(int count=0;count<numThreads;count++) {261fileOpenClose[count] = new OpenClose(fd, done);262fileOpenClose[count].start();263}264done.await();265} finally {266try {267if(raf != null) raf.close();268// fd should now no longer be valid269if(fd.valid()) {270throw new RuntimeException("FileDescriptor should not be valid");271}272// OpenClose thread tests failed273if(fail) {274throw new RuntimeException("OpenClose thread tests failed.");275}276} finally {277MultipleThreadedFD.delete();278}279}280}281282/**283* Test closeAll handling in FileDescriptor284*/285private static void TestCloseAll() throws Exception {286File testFile = new File("test");287testFile.deleteOnExit();288RandomAccessFile raf = new RandomAccessFile(testFile, "rw");289FileInputStream fis = new FileInputStream(raf.getFD());290fis.close();291if (raf.getFD().valid()) {292throw new RuntimeException("FD should not be valid.");293}294295// Test the suppressed exception handling - FileInputStream296297raf = new RandomAccessFile(testFile, "rw");298fis = new FileInputStream(raf.getFD());299BadFileInputStream bfis1 = new BadFileInputStream(raf.getFD());300BadFileInputStream bfis2 = new BadFileInputStream(raf.getFD());301BadFileInputStream bfis3 = new BadFileInputStream(raf.getFD());302// extra test - set bfis3 to null303bfis3 = null;304try {305fis.close();306} catch (IOException ioe) {307ioe.printStackTrace();308if (ioe.getSuppressed().length != 2) {309throw new RuntimeException("[FIS]Incorrect number of suppressed " +310"exceptions received : " + ioe.getSuppressed().length);311}312}313if (raf.getFD().valid()) {314// we should still have closed the FD315// even with the exception.316throw new RuntimeException("[FIS]TestCloseAll : FD still valid.");317}318319// Now test with FileOutputStream320321raf = new RandomAccessFile(testFile, "rw");322FileOutputStream fos = new FileOutputStream(raf.getFD());323BadFileOutputStream bfos1 = new BadFileOutputStream(raf.getFD());324BadFileOutputStream bfos2 = new BadFileOutputStream(raf.getFD());325BadFileOutputStream bfos3 = new BadFileOutputStream(raf.getFD());326// extra test - set bfos3 to null327bfos3 = null;328try {329fos.close();330} catch (IOException ioe) {331ioe.printStackTrace();332if (ioe.getSuppressed().length != 2) {333throw new RuntimeException("[FOS]Incorrect number of suppressed " +334"exceptions received : " + ioe.getSuppressed().length);335}336}337if (raf.getFD().valid()) {338// we should still have closed the FD339// even with the exception.340throw new RuntimeException("[FOS]TestCloseAll : FD still valid.");341}342}343344/**345* A thread which will open and close a number of FileInputStreams and346* FileOutputStreams referencing the same native file descriptor.347*/348private static class OpenClose extends Thread {349private FileDescriptor fd = null;350private CountDownLatch done;351FileInputStream[] fisArray = new FileInputStream[numFiles];352FileOutputStream[] fosArray = new FileOutputStream[numFiles];353354OpenClose(FileDescriptor filedescriptor, CountDownLatch done) {355this.fd = filedescriptor;356this.done = done;357}358359public void run() {360try {361for(int i=0;i<numFiles;i++) {362fisArray[i] = new FileInputStream(fd);363fosArray[i] = new FileOutputStream(fd);364}365366// Now close out367for(int i=0;i<numFiles;i++) {368if(fisArray[i] != null) fisArray[i].close();369if(fosArray[i] != null) fosArray[i].close();370}371372} catch(IOException ioe) {373System.out.println("OpenClose encountered IO issue :" + ioe);374fail = true;375} finally {376if (fd.valid()) { // fd should not be valid after first close() call377System.out.println("OpenClose: FileDescriptor shouldn't be valid");378fail = true;379}380done.countDown();381}382}383}384385private static class BadFileInputStream extends FileInputStream {386387BadFileInputStream(FileDescriptor fd) {388super(fd);389}390391public void close() throws IOException {392throw new IOException("Bad close operation");393}394}395396private static class BadFileOutputStream extends FileOutputStream {397398BadFileOutputStream(FileDescriptor fd) {399super(fd);400}401402public void close() throws IOException {403throw new IOException("Bad close operation");404}405}406407}408409410