changeset 5387:dcee29cd4b80

7183209: Backout 7105952 changes for jdk7u Reviewed-by: chegar, darcy, alanb
author coffeys
date Wed, 11 Jul 2012 21:48:16 +0100
parents 5b74dcc8191d
children 0039f5c7fb51
files src/share/classes/java/io/FileInputStream.java src/share/classes/java/io/FileOutputStream.java src/share/classes/java/io/RandomAccessFile.java src/solaris/classes/java/io/FileDescriptor.java src/windows/classes/java/io/FileDescriptor.java test/java/io/FileDescriptor/FileChannelFDTest.java test/java/io/FileDescriptor/Sharing.java
diffstat 7 files changed, 258 insertions(+), 576 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/io/FileInputStream.java	Wed Jul 11 13:46:50 2012 +0400
+++ b/src/share/classes/java/io/FileInputStream.java	Wed Jul 11 21:48:16 2012 +0100
@@ -56,6 +56,16 @@
     private final Object closeLock = new Object();
     private volatile boolean closed = false;
 
+    private static final ThreadLocal<Boolean> runningFinalize =
+        new ThreadLocal<>();
+
+    private static boolean isRunningFinalize() {
+        Boolean val;
+        if ((val = runningFinalize.get()) != null)
+            return val.booleanValue();
+        return false;
+    }
+
     /**
      * Creates a <code>FileInputStream</code> by
      * opening a connection to an actual file,
@@ -124,7 +134,7 @@
             throw new NullPointerException();
         }
         fd = new FileDescriptor();
-        fd.attach(this);
+        fd.incrementAndGetUseCount();
         open(name);
     }
 
@@ -164,9 +174,10 @@
 
         /*
          * FileDescriptor is being shared by streams.
-         * Register this stream with FileDescriptor tracker.
+         * Ensure that it's GC'ed only when all the streams/channels are done
+         * using it.
          */
-        fd.attach(this);
+        fd.incrementAndGetUseCount();
     }
 
     /**
@@ -293,13 +304,27 @@
             closed = true;
         }
         if (channel != null) {
+            /*
+             * Decrement the FD use count associated with the channel
+             * The use count is incremented whenever a new channel
+             * is obtained from this stream.
+             */
+           fd.decrementAndGetUseCount();
            channel.close();
         }
-        fd.closeAll(new Closeable() {
-            public void close() throws IOException {
-               close0();
-           }
-        });
+
+        /*
+         * Decrement the FD use count associated with this stream
+         */
+        int useCount = fd.decrementAndGetUseCount();
+
+        /*
+         * If FileDescriptor is still in use by another stream, the finalizer
+         * will not close it.
+         */
+        if ((useCount <= 0) || !isRunningFinalize()) {
+            close0();
+        }
     }
 
     /**
@@ -313,9 +338,7 @@
      * @see        java.io.FileDescriptor
      */
     public final FileDescriptor getFD() throws IOException {
-        if (fd != null) {
-            return fd;
-        }
+        if (fd != null) return fd;
         throw new IOException();
     }
 
@@ -339,6 +362,13 @@
         synchronized (this) {
             if (channel == null) {
                 channel = FileChannelImpl.open(fd, true, false, this);
+
+                /*
+                 * Increment fd's use count. Invoking the channel's close()
+                 * method will result in decrementing the use count set for
+                 * the channel.
+                 */
+                fd.incrementAndGetUseCount();
             }
             return channel;
         }
@@ -361,12 +391,18 @@
      */
     protected void finalize() throws IOException {
         if ((fd != null) &&  (fd != FileDescriptor.in)) {
-            /* if fd is shared, the references in FileDescriptor
-             * will ensure that finalizer is only called when
-             * safe to do so. All references using the fd have
-             * become unreachable. We can call close()
+
+            /*
+             * Finalizer should not release the FileDescriptor if another
+             * stream is still using it. If the user directly invokes
+             * close() then the FileDescriptor is also released.
              */
-            close();
+            runningFinalize.set(Boolean.TRUE);
+            try {
+                close();
+            } finally {
+                runningFinalize.set(Boolean.FALSE);
+            }
         }
     }
 }
--- a/src/share/classes/java/io/FileOutputStream.java	Wed Jul 11 13:46:50 2012 +0400
+++ b/src/share/classes/java/io/FileOutputStream.java	Wed Jul 11 21:48:16 2012 +0100
@@ -69,6 +69,15 @@
 
     private final Object closeLock = new Object();
     private volatile boolean closed = false;
+    private static final ThreadLocal<Boolean> runningFinalize =
+        new ThreadLocal<>();
+
+    private static boolean isRunningFinalize() {
+        Boolean val;
+        if ((val = runningFinalize.get()) != null)
+            return val.booleanValue();
+        return false;
+    }
 
     /**
      * Creates a file output stream to write to the file with the
@@ -199,7 +208,7 @@
         this.fd = new FileDescriptor();
         this.append = append;
 
-        fd.attach(this);
+        fd.incrementAndGetUseCount();
         open(name, append);
     }
 
@@ -236,7 +245,13 @@
         }
         this.fd = fdObj;
         this.append = false;
-        fd.attach(this);
+
+        /*
+         * FileDescriptor is being shared by streams.
+         * Ensure that it's GC'ed only when all the streams/channels are done
+         * using it.
+         */
+        fd.incrementAndGetUseCount();
     }
 
     /**
@@ -325,13 +340,27 @@
         }
 
         if (channel != null) {
+            /*
+             * Decrement FD use count associated with the channel
+             * The use count is incremented whenever a new channel
+             * is obtained from this stream.
+             */
+            fd.decrementAndGetUseCount();
             channel.close();
         }
-        fd.closeAll(new Closeable() {
-            public void close() throws IOException {
-               close0();
-           }
-        });
+
+        /*
+         * Decrement FD use count associated with this stream
+         */
+        int useCount = fd.decrementAndGetUseCount();
+
+        /*
+         * If FileDescriptor is still in use by another stream, the finalizer
+         * will not close it.
+         */
+        if ((useCount <= 0) || !isRunningFinalize()) {
+            close0();
+        }
     }
 
     /**
@@ -345,9 +374,7 @@
      * @see        java.io.FileDescriptor
      */
      public final FileDescriptor getFD()  throws IOException {
-        if (fd != null) {
-            return fd;
-        }
+        if (fd != null) return fd;
         throw new IOException();
      }
 
@@ -372,6 +399,13 @@
         synchronized (this) {
             if (channel == null) {
                 channel = FileChannelImpl.open(fd, false, true, append, this);
+
+                /*
+                 * Increment fd's use count. Invoking the channel's close()
+                 * method will result in decrementing the use count set for
+                 * the channel.
+                 */
+                fd.incrementAndGetUseCount();
             }
             return channel;
         }
@@ -390,12 +424,18 @@
             if (fd == FileDescriptor.out || fd == FileDescriptor.err) {
                 flush();
             } else {
-                /* if fd is shared, the references in FileDescriptor
-                 * will ensure that finalizer is only called when
-                 * safe to do so. All references using the fd have
-                 * become unreachable. We can call close()
+
+                /*
+                 * Finalizer should not release the FileDescriptor if another
+                 * stream is still using it. If the user directly invokes
+                 * close() then the FileDescriptor is also released.
                  */
-                close();
+                runningFinalize.set(Boolean.TRUE);
+                try {
+                    close();
+                } finally {
+                    runningFinalize.set(Boolean.FALSE);
+                }
             }
         }
     }
--- a/src/share/classes/java/io/RandomAccessFile.java	Wed Jul 11 13:46:50 2012 +0400
+++ b/src/share/classes/java/io/RandomAccessFile.java	Wed Jul 11 21:48:16 2012 +0100
@@ -229,7 +229,7 @@
             throw new NullPointerException();
         }
         fd = new FileDescriptor();
-        fd.attach(this);
+        fd.incrementAndGetUseCount();
         open(name, imode);
     }
 
@@ -242,9 +242,7 @@
      * @see        java.io.FileDescriptor
      */
     public final FileDescriptor getFD() throws IOException {
-        if (fd != null) {
-            return fd;
-        }
+        if (fd != null) return fd;
         throw new IOException();
     }
 
@@ -270,6 +268,17 @@
         synchronized (this) {
             if (channel == null) {
                 channel = FileChannelImpl.open(fd, true, rw, this);
+
+                /*
+                 * FileDescriptor could be shared by FileInputStream or
+                 * FileOutputStream.
+                 * Ensure that FD is GC'ed only when all the streams/channels
+                 * are done using it.
+                 * Increment fd's use count. Invoking the channel's close()
+                 * method will result in decrementing the use count set for
+                 * the channel.
+                 */
+                fd.incrementAndGetUseCount();
             }
             return channel;
         }
@@ -568,13 +577,21 @@
             closed = true;
         }
         if (channel != null) {
+            /*
+             * Decrement FD use count associated with the channel. The FD use
+             * count is incremented whenever a new channel is obtained from
+             * this stream.
+             */
+            fd.decrementAndGetUseCount();
             channel.close();
         }
-        fd.closeAll(new Closeable() {
-            public void close() throws IOException {
-               close0();
-           }
-        });
+
+        /*
+         * Decrement FD use count associated with this stream.
+         * The count got incremented by FileDescriptor during its construction.
+         */
+        fd.decrementAndGetUseCount();
+        close0();
     }
 
     //
--- a/src/solaris/classes/java/io/FileDescriptor.java	Wed Jul 11 13:46:50 2012 +0400
+++ b/src/solaris/classes/java/io/FileDescriptor.java	Wed Jul 11 21:48:16 2012 +0100
@@ -24,8 +24,8 @@
  */
 
 package java.io;
-import java.util.ArrayList;
-import java.util.List;
+
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * Instances of the file descriptor class serve as an opaque handle
@@ -45,9 +45,13 @@
 public final class FileDescriptor {
 
     private int fd;
-    private Closeable parent;
-    private List<Closeable> otherParents;
-    private boolean closed;
+
+    /**
+     * A counter for tracking the FIS/FOS/RAF instances that
+     * use this FileDescriptor. The FIS/FOS.finalize() will not release
+     * the FileDescriptor if it is still under user by a stream.
+     */
+    private AtomicInteger useCount;
 
     /**
      * Constructs an (invalid) FileDescriptor
@@ -55,10 +59,12 @@
      */
     public /**/ FileDescriptor() {
         fd = -1;
+        useCount = new AtomicInteger();
     }
 
     private /* */ FileDescriptor(int fd) {
         this.fd = fd;
+        useCount = new AtomicInteger();
     }
 
     /**
@@ -158,67 +164,13 @@
         );
     }
 
-    /*
-     * Package private methods to track referents.
-     * If multiple streams point to the same FileDescriptor, we cycle
-     * through the list of all referents and call close()
-     */
+    // package private methods used by FIS, FOS and RAF
 
-    /**
-     * Attach a Closeable to this FD for tracking.
-     * parent reference is added to otherParents when
-     * needed to make closeAll simpler.
-     */
-    synchronized void attach(Closeable c) {
-        if (parent == null) {
-            // first caller gets to do this
-            parent = c;
-        } else if (otherParents == null) {
-            otherParents = new ArrayList<>();
-            otherParents.add(parent);
-            otherParents.add(c);
-        } else {
-            otherParents.add(c);
-        }
+    int incrementAndGetUseCount() {
+        return useCount.incrementAndGet();
     }
 
-    /**
-     * Cycle through all Closeables sharing this FD and call
-     * close() on each one.
-     *
-     * The caller closeable gets to call close0().
-     */
-    @SuppressWarnings("try")
-    synchronized void closeAll(Closeable releaser) throws IOException {
-        if (!closed) {
-            closed = true;
-            IOException ioe = null;
-            try (Closeable c = releaser) {
-                if (otherParents != null) {
-                    for (Closeable referent : otherParents) {
-                        try {
-                            referent.close();
-                        } catch(IOException x) {
-                            if (ioe == null) {
-                                ioe = x;
-                            } else {
-                                ioe.addSuppressed(x);
-                            }
-                        }
-                    }
-                }
-            } catch(IOException ex) {
-                /*
-                 * If releaser close() throws IOException
-                 * add other exceptions as suppressed.
-                 */
-                if (ioe != null)
-                    ex.addSuppressed(ioe);
-                ioe = ex;
-            } finally {
-                if (ioe != null)
-                    throw ioe;
-            }
-        }
+    int decrementAndGetUseCount() {
+        return useCount.decrementAndGet();
     }
 }
--- a/src/windows/classes/java/io/FileDescriptor.java	Wed Jul 11 13:46:50 2012 +0400
+++ b/src/windows/classes/java/io/FileDescriptor.java	Wed Jul 11 21:48:16 2012 +0100
@@ -24,8 +24,8 @@
  */
 
 package java.io;
-import java.util.ArrayList;
-import java.util.List;
+
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * Instances of the file descriptor class serve as an opaque handle
@@ -42,10 +42,16 @@
 public final class FileDescriptor {
 
     private int fd;
+
     private long handle;
-    private Closeable parent;
-    private List<Closeable> otherParents;
-    private boolean closed;
+
+    /**
+     * A use counter for tracking the FIS/FOS/RAF instances that
+     * use this FileDescriptor. The FIS/FOS.finalize() will not release
+     * the FileDescriptor if it is still under use by any stream.
+     */
+    private AtomicInteger useCount;
+
 
     /**
      * Constructs an (invalid) FileDescriptor
@@ -54,6 +60,7 @@
     public /**/ FileDescriptor() {
         fd = -1;
         handle = -1;
+        useCount = new AtomicInteger();
     }
 
     static {
@@ -161,67 +168,13 @@
         return desc;
     }
 
-    /*
-     * Package private methods to track referents.
-     * If multiple streams point to the same FileDescriptor, we cycle
-     * through the list of all referents and call close()
-     */
+    // package private methods used by FIS, FOS and RAF.
 
-    /**
-     * Attach a Closeable to this FD for tracking.
-     * parent reference is added to otherParents when
-     * needed to make closeAll simpler.
-     */
-    synchronized void attach(Closeable c) {
-        if (parent == null) {
-            // first caller gets to do this
-            parent = c;
-        } else if (otherParents == null) {
-            otherParents = new ArrayList<>();
-            otherParents.add(parent);
-            otherParents.add(c);
-        } else {
-            otherParents.add(c);
-        }
+    int incrementAndGetUseCount() {
+        return useCount.incrementAndGet();
     }
 
-    /**
-     * Cycle through all Closeables sharing this FD and call
-     * close() on each one.
-     *
-     * The caller closeable gets to call close0().
-     */
-    @SuppressWarnings("try")
-    synchronized void closeAll(Closeable releaser) throws IOException {
-        if (!closed) {
-            closed = true;
-            IOException ioe = null;
-            try (Closeable c = releaser) {
-                if (otherParents != null) {
-                    for (Closeable referent : otherParents) {
-                        try {
-                            referent.close();
-                        } catch(IOException x) {
-                            if (ioe == null) {
-                                ioe = x;
-                            } else {
-                                ioe.addSuppressed(x);
-                            }
-                        }
-                    }
-                }
-            } catch(IOException ex) {
-                /*
-                 * If releaser close() throws IOException
-                 * add other exceptions as suppressed.
-                 */
-                if (ioe != null)
-                    ex.addSuppressed(ioe);
-                ioe = ex;
-            } finally {
-                if (ioe != null)
-                    throw ioe;
-            }
-        }
+    int decrementAndGetUseCount() {
+        return useCount.decrementAndGet();
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/io/FileDescriptor/FileChannelFDTest.java	Wed Jul 11 21:48:16 2012 +0100
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2006, 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 6322678
+ * @summary Test for making sure that fd is closed during
+ *          finalization of a stream, when an associated
+ *          file channel is not available
+ */
+
+import java.io.*;
+import java.nio.*;
+import java.nio.channels.*;
+
+public class FileChannelFDTest {
+
+    static byte data[] = new byte[] {48, 49, 50, 51, 52, 53, 54, 55, 56, 57,};
+    static String inFileName = "fd-in-test.txt";
+    static String outFileName = "fd-out-test.txt";
+    static File inFile;
+    static File outFile;
+
+    private static void writeToInFile() throws IOException {
+        FileOutputStream out = new FileOutputStream(inFile);
+        out.write(data);
+        out.close();
+    }
+
+    public static void main(String[] args)
+                throws Exception {
+
+        inFile= new File(System.getProperty("test.dir", "."),
+                        inFileName);
+        inFile.createNewFile();
+        inFile.deleteOnExit();
+        writeToInFile();
+
+        outFile  = new File(System.getProperty("test.dir", "."),
+                        outFileName);
+        outFile.createNewFile();
+        outFile.deleteOnExit();
+
+        doFileChannel();
+    }
+
+     private static void doFileChannel() throws Exception {
+
+        FileInputStream fis = new FileInputStream(inFile);
+        FileDescriptor fd = fis.getFD();
+        FileChannel fc = fis.getChannel();
+        System.out.println("Created fis:" + fis);
+
+        /**
+         * Encourage the GC
+         */
+        fis = null;
+        fc = null;
+        System.gc();
+        Thread.sleep(500);
+
+        if (fd.valid()) {
+            throw new Exception("Finalizer either didn't run --" +
+                "try increasing the Thread's sleep time after System.gc();" +
+                "or the finalizer didn't close the file");
+        }
+
+        System.out.println("File Closed successfully");
+        System.out.println();
+  }
+}
--- a/test/java/io/FileDescriptor/Sharing.java	Wed Jul 11 13:46:50 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,408 +0,0 @@
-/*
- * Copyright (c) 2012, 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<numThreads;count++) {
-                fileOpenClose[count] = new OpenClose(fd, done);
-                fileOpenClose[count].start();
-            }
-            done.await();
-        } finally {
-            try {
-                if(raf != null) raf.close();
-                // fd should now no longer be valid
-                if(fd.valid()) {
-                    throw new RuntimeException("FileDescriptor should not be valid");
-                }
-                // OpenClose thread tests failed
-                if(fail) {
-                    throw new RuntimeException("OpenClose thread tests failed.");
-                }
-            } finally {
-                MultipleThreadedFD.delete();
-            }
-        }
-    }
-
-    /**
-     * Test closeAll handling in FileDescriptor
-     */
-    private static void TestCloseAll() throws Exception {
-        File testFile = new File("test");
-        testFile.deleteOnExit();
-        RandomAccessFile raf = new RandomAccessFile(testFile, "rw");
-        FileInputStream fis = new FileInputStream(raf.getFD());
-        fis.close();
-        if (raf.getFD().valid()) {
-             throw new RuntimeException("FD should not be valid.");
-        }
-
-        // Test the suppressed exception handling - FileInputStream
-
-        raf = new RandomAccessFile(testFile, "rw");
-        fis = new FileInputStream(raf.getFD());
-        BadFileInputStream bfis1 = new BadFileInputStream(raf.getFD());
-        BadFileInputStream bfis2 = new BadFileInputStream(raf.getFD());
-        BadFileInputStream bfis3 = new BadFileInputStream(raf.getFD());
-        // extra test - set bfis3 to null
-        bfis3 = null;
-        try {
-            fis.close();
-        } catch (IOException ioe) {
-            ioe.printStackTrace();
-            if (ioe.getSuppressed().length != 2) {
-                throw new RuntimeException("[FIS]Incorrect number of suppressed " +
-                          "exceptions received : " + ioe.getSuppressed().length);
-            }
-        }
-        if (raf.getFD().valid()) {
-            // we should still have closed the FD
-            // even with the exception.
-            throw new RuntimeException("[FIS]TestCloseAll : FD still valid.");
-        }
-
-        // Now test with FileOutputStream
-
-        raf = new RandomAccessFile(testFile, "rw");
-        FileOutputStream fos = new FileOutputStream(raf.getFD());
-        BadFileOutputStream bfos1 = new BadFileOutputStream(raf.getFD());
-        BadFileOutputStream bfos2 = new BadFileOutputStream(raf.getFD());
-        BadFileOutputStream bfos3 = new BadFileOutputStream(raf.getFD());
-        // extra test - set bfos3 to null
-        bfos3 = null;
-        try {
-            fos.close();
-        } catch (IOException ioe) {
-            ioe.printStackTrace();
-            if (ioe.getSuppressed().length != 2) {
-                throw new RuntimeException("[FOS]Incorrect number of suppressed " +
-                          "exceptions received : " + ioe.getSuppressed().length);
-            }
-        }
-        if (raf.getFD().valid()) {
-            // we should still have closed the FD
-            // even with the exception.
-            throw new RuntimeException("[FOS]TestCloseAll : FD still valid.");
-        }
-    }
-
-    /**
-     * A thread which will open and close a number of FileInputStreams and
-     * FileOutputStreams referencing the same native file descriptor.
-     */
-    private static class OpenClose extends Thread {
-        private FileDescriptor fd = null;
-        private CountDownLatch done;
-        FileInputStream[] fisArray = new FileInputStream[numFiles];
-        FileOutputStream[] fosArray = new FileOutputStream[numFiles];
-
-        OpenClose(FileDescriptor filedescriptor, CountDownLatch done) {
-            this.fd = filedescriptor;
-            this.done = done;
-        }
-
-        public void run() {
-             try {
-                 for(int i=0;i<numFiles;i++) {
-                     fisArray[i] = new FileInputStream(fd);
-                     fosArray[i] = new FileOutputStream(fd);
-                 }
-
-                 // Now close out
-                 for(int i=0;i<numFiles;i++) {
-                     if(fisArray[i] != null) fisArray[i].close();
-                     if(fosArray[i] != null) fosArray[i].close();
-                 }
-
-             } catch(IOException ioe) {
-                 System.out.println("OpenClose encountered IO issue :" + ioe);
-                 fail = true;
-             } finally {
-                 if (fd.valid()) { // fd should not be valid after first close() call
-                     System.out.println("OpenClose: FileDescriptor shouldn't be valid");
-                     fail = true;
-                 }
-                 done.countDown();
-             }
-         }
-    }
-
-    private static class BadFileInputStream extends FileInputStream {
-
-        BadFileInputStream(FileDescriptor fd) {
-            super(fd);
-        }
-
-        public void close() throws IOException {
-            throw new IOException("Bad close operation");
-        }
-    }
-
-    private static class BadFileOutputStream extends FileOutputStream {
-
-        BadFileOutputStream(FileDescriptor fd) {
-            super(fd);
-        }
-
-        public void close() throws IOException {
-            throw new IOException("Bad close operation");
-        }
-    }
-
-}