src/java.base/windows/classes/java/io/FileDescriptor.java
changeset 48941 4f11514fe783
parent 48940 ca22f8cb0c9b
child 48942 a6c4b85163c1
equal deleted inserted replaced
48940:ca22f8cb0c9b 48941:4f11514fe783
     1 /*
       
     2  * Copyright (c) 2003, 2018, 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.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package java.io;
       
    27 
       
    28 import java.lang.ref.Cleaner;
       
    29 import java.util.ArrayList;
       
    30 import java.util.List;
       
    31 
       
    32 import jdk.internal.misc.JavaIOFileDescriptorAccess;
       
    33 import jdk.internal.misc.SharedSecrets;
       
    34 import jdk.internal.ref.CleanerFactory;
       
    35 import jdk.internal.ref.PhantomCleanable;
       
    36 
       
    37 /**
       
    38  * Instances of the file descriptor class serve as an opaque handle
       
    39  * to the underlying machine-specific structure representing an open
       
    40  * file, an open socket, or another source or sink of bytes.
       
    41  * The main practical use for a file descriptor is to create a
       
    42  * {@link FileInputStream} or {@link FileOutputStream} to contain it.
       
    43  * <p>
       
    44  * Applications should not create their own file descriptors.
       
    45  *
       
    46  * @author  Pavani Diwanji
       
    47  * @since   1.0
       
    48  */
       
    49 public final class FileDescriptor {
       
    50 
       
    51     private int fd;
       
    52 
       
    53     private long handle;
       
    54 
       
    55     private Closeable parent;
       
    56     private List<Closeable> otherParents;
       
    57     private boolean closed;
       
    58 
       
    59     /**
       
    60      * true, if file is opened for appending.
       
    61      */
       
    62     private boolean append;
       
    63 
       
    64     static {
       
    65         initIDs();
       
    66     }
       
    67 
       
    68     // Set up JavaIOFileDescriptorAccess in SharedSecrets
       
    69     static {
       
    70         SharedSecrets.setJavaIOFileDescriptorAccess(
       
    71                 new JavaIOFileDescriptorAccess() {
       
    72                     public void set(FileDescriptor fdo, int fd) {
       
    73                         fdo.fd = fd;
       
    74                     }
       
    75 
       
    76                     public int get(FileDescriptor fdo) {
       
    77                         return fdo.fd;
       
    78                     }
       
    79 
       
    80                     public void setAppend(FileDescriptor fdo, boolean append) {
       
    81                         fdo.append = append;
       
    82                     }
       
    83 
       
    84                     public boolean getAppend(FileDescriptor fdo) {
       
    85                         return fdo.append;
       
    86                     }
       
    87 
       
    88                     public void close(FileDescriptor fdo) throws IOException {
       
    89                         fdo.close();
       
    90                     }
       
    91 
       
    92                     public void registerCleanup(FileDescriptor fdo) {
       
    93                         fdo.registerCleanup(null);
       
    94                     }
       
    95 
       
    96                     public void registerCleanup(FileDescriptor fdo, PhantomCleanable<Object> cleanup) {
       
    97                         fdo.registerCleanup(cleanup);
       
    98                     }
       
    99 
       
   100                     public void unregisterCleanup(FileDescriptor fdo) {
       
   101                         fdo.unregisterCleanup();
       
   102                     }
       
   103 
       
   104                     public void setHandle(FileDescriptor fdo, long handle) {
       
   105                         fdo.setHandle(handle);
       
   106                     }
       
   107 
       
   108                     public long getHandle(FileDescriptor fdo) {
       
   109                         return fdo.handle;
       
   110                     }
       
   111                 }
       
   112         );
       
   113     }
       
   114 
       
   115     /**
       
   116      * Cleanup in case FileDescriptor is not explicitly closed.
       
   117      */
       
   118     private PhantomCleanable<Object> cleanup;
       
   119 
       
   120     /**
       
   121      * Constructs an (invalid) FileDescriptor
       
   122      * object.
       
   123      */
       
   124     public FileDescriptor() {
       
   125         fd = -1;
       
   126         handle = -1;
       
   127     }
       
   128 
       
   129     /**
       
   130      * A handle to the standard input stream. Usually, this file
       
   131      * descriptor is not used directly, but rather via the input stream
       
   132      * known as {@code System.in}.
       
   133      *
       
   134      * @see     java.lang.System#in
       
   135      */
       
   136     public static final FileDescriptor in = standardStream(0);
       
   137 
       
   138     /**
       
   139      * A handle to the standard output stream. Usually, this file
       
   140      * descriptor is not used directly, but rather via the output stream
       
   141      * known as {@code System.out}.
       
   142      * @see     java.lang.System#out
       
   143      */
       
   144     public static final FileDescriptor out = standardStream(1);
       
   145 
       
   146     /**
       
   147      * A handle to the standard error stream. Usually, this file
       
   148      * descriptor is not used directly, but rather via the output stream
       
   149      * known as {@code System.err}.
       
   150      *
       
   151      * @see     java.lang.System#err
       
   152      */
       
   153     public static final FileDescriptor err = standardStream(2);
       
   154 
       
   155     /**
       
   156      * Tests if this file descriptor object is valid.
       
   157      *
       
   158      * @return  {@code true} if the file descriptor object represents a
       
   159      *          valid, open file, socket, or other active I/O connection;
       
   160      *          {@code false} otherwise.
       
   161      */
       
   162     public boolean valid() {
       
   163         return (handle != -1) || (fd != -1);
       
   164     }
       
   165 
       
   166     /**
       
   167      * Force all system buffers to synchronize with the underlying
       
   168      * device.  This method returns after all modified data and
       
   169      * attributes of this FileDescriptor have been written to the
       
   170      * relevant device(s).  In particular, if this FileDescriptor
       
   171      * refers to a physical storage medium, such as a file in a file
       
   172      * system, sync will not return until all in-memory modified copies
       
   173      * of buffers associated with this FileDescriptor have been
       
   174      * written to the physical medium.
       
   175      *
       
   176      * sync is meant to be used by code that requires physical
       
   177      * storage (such as a file) to be in a known state  For
       
   178      * example, a class that provided a simple transaction facility
       
   179      * might use sync to ensure that all changes to a file caused
       
   180      * by a given transaction were recorded on a storage medium.
       
   181      *
       
   182      * sync only affects buffers downstream of this FileDescriptor.  If
       
   183      * any in-memory buffering is being done by the application (for
       
   184      * example, by a BufferedOutputStream object), those buffers must
       
   185      * be flushed into the FileDescriptor (for example, by invoking
       
   186      * OutputStream.flush) before that data will be affected by sync.
       
   187      *
       
   188      * @exception SyncFailedException
       
   189      *        Thrown when the buffers cannot be flushed,
       
   190      *        or because the system cannot guarantee that all the
       
   191      *        buffers have been synchronized with physical media.
       
   192      * @since     1.1
       
   193      */
       
   194     public native void sync() throws SyncFailedException;
       
   195 
       
   196     /* This routine initializes JNI field offsets for the class */
       
   197     private static native void initIDs();
       
   198 
       
   199     private static FileDescriptor standardStream(int fd) {
       
   200         FileDescriptor desc = new FileDescriptor();
       
   201         desc.handle = getHandle(fd);
       
   202         return desc;
       
   203     }
       
   204 
       
   205     private static native long getHandle(int d);
       
   206 
       
   207     /**
       
   208      * Set the handle.
       
   209      * If setting to -1, clear the cleaner.
       
   210      * The {@link #registerCleanup()} method should be called for new handles.
       
   211      * @param handle the handle or -1 to indicate closed
       
   212      */
       
   213     @SuppressWarnings("unchecked")
       
   214     void setHandle(long handle) {
       
   215         if (handle == -1 && cleanup != null) {
       
   216             cleanup.clear();
       
   217             cleanup = null;
       
   218         }
       
   219         this.handle = handle;
       
   220     }
       
   221 
       
   222     /**
       
   223      * Register a cleanup for the current handle.
       
   224      * Used directly in java.io and indirectly via fdAccess.
       
   225      * The cleanup should be registered after the handle is set in the FileDescriptor.
       
   226      */
       
   227     @SuppressWarnings("unchecked")
       
   228     void registerCleanup() {
       
   229         registerCleanup(null);
       
   230     }
       
   231 
       
   232     /**
       
   233      * Register a cleanup for the current handle.
       
   234      * Used directly in java.io and indirectly via fdAccess.
       
   235      * The cleanup should be registered after the handle is set in the FileDescriptor.
       
   236      * @param newCleanable a PhantomCleanable to register
       
   237      */
       
   238     @SuppressWarnings("unchecked")
       
   239     synchronized void registerCleanup(PhantomCleanable<Object> newCleanable) {
       
   240         if (cleanup != null) {
       
   241             cleanup.clear();
       
   242         }
       
   243         cleanup = (newCleanable == null) ? FDCleanup.create(this) : newCleanable;
       
   244     }
       
   245 
       
   246    /**
       
   247      * Unregister a cleanup for the current raw fd.
       
   248      * Used directly in java.io and indirectly via fdAccess.
       
   249      * Normally {@link #close()} should be used except in cases where
       
   250      * it is certain the caller will close the raw fd and the cleanup
       
   251      * must not close the raw fd.  {@link #unregisterCleanup()} must be
       
   252      * called before the raw fd is closed to prevent a race that makes
       
   253      * it possible for the fd to be reallocated to another use and later
       
   254      * the cleanup might be invoked.
       
   255      */
       
   256     synchronized void unregisterCleanup() {
       
   257         if (cleanup != null) {
       
   258             cleanup.clear();
       
   259         }
       
   260         cleanup = null;
       
   261     }
       
   262 
       
   263     /**
       
   264      * Close the raw file descriptor or handle, if it has not already been closed
       
   265      * and set the fd and handle to -1.
       
   266      * Clear the cleaner so the close does not happen twice.
       
   267      * Package private to allow it to be used in java.io.
       
   268      * @throws IOException if close fails
       
   269      */
       
   270     @SuppressWarnings("unchecked")
       
   271     synchronized void close() throws IOException {
       
   272         if (cleanup != null) {
       
   273             cleanup.clear();
       
   274             cleanup = null;
       
   275         }
       
   276         close0();
       
   277     }
       
   278 
       
   279     /*
       
   280      * Close the raw file descriptor or handle, if it has not already been closed
       
   281      * and set the fd and handle to -1.
       
   282      */
       
   283     private native void close0() throws IOException;
       
   284 
       
   285     /*
       
   286     * Raw close of the file handle.
       
   287     * Used only for last chance cleanup.
       
   288     */
       
   289     private static native void cleanupClose0(long handle) throws IOException;
       
   290 
       
   291     /*
       
   292      * Package private methods to track referents.
       
   293      * If multiple streams point to the same FileDescriptor, we cycle
       
   294      * through the list of all referents and call close()
       
   295      */
       
   296 
       
   297     /**
       
   298      * Attach a Closeable to this FD for tracking.
       
   299      * parent reference is added to otherParents when
       
   300      * needed to make closeAll simpler.
       
   301      */
       
   302     synchronized void attach(Closeable c) {
       
   303         if (parent == null) {
       
   304             // first caller gets to do this
       
   305             parent = c;
       
   306         } else if (otherParents == null) {
       
   307             otherParents = new ArrayList<>();
       
   308             otherParents.add(parent);
       
   309             otherParents.add(c);
       
   310         } else {
       
   311             otherParents.add(c);
       
   312         }
       
   313     }
       
   314 
       
   315     /**
       
   316      * Cycle through all Closeables sharing this FD and call
       
   317      * close() on each one.
       
   318      *
       
   319      * The caller closeable gets to call close0().
       
   320      */
       
   321     @SuppressWarnings("try")
       
   322     synchronized void closeAll(Closeable releaser) throws IOException {
       
   323         if (!closed) {
       
   324             closed = true;
       
   325             IOException ioe = null;
       
   326             try (releaser) {
       
   327                 if (otherParents != null) {
       
   328                     for (Closeable referent : otherParents) {
       
   329                         try {
       
   330                             referent.close();
       
   331                         } catch(IOException x) {
       
   332                             if (ioe == null) {
       
   333                                 ioe = x;
       
   334                             } else {
       
   335                                 ioe.addSuppressed(x);
       
   336                             }
       
   337                         }
       
   338                     }
       
   339                 }
       
   340             } catch(IOException ex) {
       
   341                 /*
       
   342                  * If releaser close() throws IOException
       
   343                  * add other exceptions as suppressed.
       
   344                  */
       
   345                 if (ioe != null)
       
   346                     ex.addSuppressed(ioe);
       
   347                 ioe = ex;
       
   348             } finally {
       
   349                 if (ioe != null)
       
   350                     throw ioe;
       
   351             }
       
   352         }
       
   353     }
       
   354 
       
   355     /**
       
   356      * Cleanup for a FileDescriptor when it becomes phantom reachable.
       
   357      * Create a cleanup if handle != -1.
       
   358      * Windows closes files using handles and sockets via the fd.
       
   359      * Network FileDescriptors using socket fd must provide their
       
   360      * own PhantomCleanable to {@link #registerCleanup}.
       
   361      * This implementation only clears thehandles.
       
   362      * <p>
       
   363      * Subclassed from {@code PhantomCleanable} so that {@code clear} can be
       
   364      * called to disable the cleanup when the handle is closed by any means other
       
   365      * than calling {@link FileDescriptor#close}.
       
   366      * Otherwise, it may incorrectly close the handle after it has been reused.
       
   367      */
       
   368     static final class FDCleanup extends PhantomCleanable<Object> {
       
   369         private final long handle;
       
   370 
       
   371         static FDCleanup create(FileDescriptor fdo) {
       
   372             return fdo.handle == -1L
       
   373                     ? null
       
   374                     : new FDCleanup(fdo, CleanerFactory.cleaner(), fdo.handle);
       
   375         }
       
   376 
       
   377         /**
       
   378          * Constructor for a phantom cleanable reference.
       
   379          * @param obj the object to monitor
       
   380          * @param cleaner the cleaner
       
   381          * @param handle file handle to close
       
   382          */
       
   383         private FDCleanup(Object obj, Cleaner cleaner, long handle) {
       
   384             super(obj, cleaner);
       
   385             this.handle = handle;
       
   386         }
       
   387 
       
   388         /**
       
   389          * Close the native handle.
       
   390          */
       
   391         @Override
       
   392         protected void performCleanup() {
       
   393             try {
       
   394                 cleanupClose0(handle);
       
   395             } catch (IOException ioe) {
       
   396                 throw new UncheckedIOException("close", ioe);
       
   397             }
       
   398         }
       
   399     }
       
   400 }