src/java.base/unix/classes/java/io/FileDescriptor.java
branchihse-cflags-rewrite-branch
changeset 56169 8ab1a1ee2af6
parent 56168 cb0b10e44247
parent 48987 513e98643998
child 56170 d509ae946997
equal deleted inserted replaced
56168:cb0b10e44247 56169:8ab1a1ee2af6
     1 /*
       
     2  * Copyright (c) 1995, 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 Closeable parent;
       
    54     private List<Closeable> otherParents;
       
    55     private boolean closed;
       
    56 
       
    57     /**
       
    58      * true, if file is opened for appending.
       
    59      */
       
    60     private boolean append;
       
    61 
       
    62     static {
       
    63         initIDs();
       
    64     }
       
    65 
       
    66     // Set up JavaIOFileDescriptorAccess in SharedSecrets
       
    67     static {
       
    68         SharedSecrets.setJavaIOFileDescriptorAccess(
       
    69                 new JavaIOFileDescriptorAccess() {
       
    70                     public void set(FileDescriptor fdo, int fd) {
       
    71                         fdo.set(fd);
       
    72                     }
       
    73 
       
    74                     public int get(FileDescriptor fdo) {
       
    75                         return fdo.fd;
       
    76                     }
       
    77 
       
    78                     public void setAppend(FileDescriptor fdo, boolean append) {
       
    79                         fdo.append = append;
       
    80                     }
       
    81 
       
    82                     public boolean getAppend(FileDescriptor fdo) {
       
    83                         return fdo.append;
       
    84                     }
       
    85 
       
    86                     public void close(FileDescriptor fdo) throws IOException {
       
    87                         fdo.close();
       
    88                     }
       
    89 
       
    90                     public void registerCleanup(FileDescriptor fdo) {
       
    91                         fdo.registerCleanup();
       
    92                     }
       
    93 
       
    94                     public void registerCleanup(FileDescriptor fdo, PhantomCleanable<Object> cleanup) {
       
    95                         fdo.registerCleanup(cleanup);
       
    96                     }
       
    97 
       
    98                     public void unregisterCleanup(FileDescriptor fdo) {
       
    99                         fdo.unregisterCleanup();
       
   100                     }
       
   101 
       
   102                     public void setHandle(FileDescriptor fdo, long handle) {
       
   103                         throw new UnsupportedOperationException();
       
   104                     }
       
   105 
       
   106                     public long getHandle(FileDescriptor fdo) {
       
   107                         throw new UnsupportedOperationException();
       
   108                     }
       
   109                 }
       
   110         );
       
   111     }
       
   112 
       
   113     /**
       
   114      * Cleanup in case FileDescriptor is not explicitly closed.
       
   115      */
       
   116     private PhantomCleanable<Object> cleanup;
       
   117 
       
   118     /**
       
   119      * Constructs an (invalid) FileDescriptor
       
   120      * object.
       
   121      */
       
   122     public FileDescriptor() {
       
   123         fd = -1;
       
   124     }
       
   125 
       
   126     private FileDescriptor(int fd) {
       
   127         this.fd = fd;
       
   128         this.append = getAppend(fd);
       
   129     }
       
   130 
       
   131     /**
       
   132      * A handle to the standard input stream. Usually, this file
       
   133      * descriptor is not used directly, but rather via the input stream
       
   134      * known as {@code System.in}.
       
   135      *
       
   136      * @see     java.lang.System#in
       
   137      */
       
   138     public static final FileDescriptor in = new FileDescriptor(0);
       
   139 
       
   140     /**
       
   141      * A handle to the standard output stream. Usually, this file
       
   142      * descriptor is not used directly, but rather via the output stream
       
   143      * known as {@code System.out}.
       
   144      * @see     java.lang.System#out
       
   145      */
       
   146     public static final FileDescriptor out = new FileDescriptor(1);
       
   147 
       
   148     /**
       
   149      * A handle to the standard error stream. Usually, this file
       
   150      * descriptor is not used directly, but rather via the output stream
       
   151      * known as {@code System.err}.
       
   152      *
       
   153      * @see     java.lang.System#err
       
   154      */
       
   155     public static final FileDescriptor err = new FileDescriptor(2);
       
   156 
       
   157     /**
       
   158      * Tests if this file descriptor object is valid.
       
   159      *
       
   160      * @return  {@code true} if the file descriptor object represents a
       
   161      *          valid, open file, socket, or other active I/O connection;
       
   162      *          {@code false} otherwise.
       
   163      */
       
   164     public boolean valid() {
       
   165         return fd != -1;
       
   166     }
       
   167 
       
   168     /**
       
   169      * Force all system buffers to synchronize with the underlying
       
   170      * device.  This method returns after all modified data and
       
   171      * attributes of this FileDescriptor have been written to the
       
   172      * relevant device(s).  In particular, if this FileDescriptor
       
   173      * refers to a physical storage medium, such as a file in a file
       
   174      * system, sync will not return until all in-memory modified copies
       
   175      * of buffers associated with this FileDescriptor have been
       
   176      * written to the physical medium.
       
   177      *
       
   178      * sync is meant to be used by code that requires physical
       
   179      * storage (such as a file) to be in a known state  For
       
   180      * example, a class that provided a simple transaction facility
       
   181      * might use sync to ensure that all changes to a file caused
       
   182      * by a given transaction were recorded on a storage medium.
       
   183      *
       
   184      * sync only affects buffers downstream of this FileDescriptor.  If
       
   185      * any in-memory buffering is being done by the application (for
       
   186      * example, by a BufferedOutputStream object), those buffers must
       
   187      * be flushed into the FileDescriptor (for example, by invoking
       
   188      * OutputStream.flush) before that data will be affected by sync.
       
   189      *
       
   190      * @exception SyncFailedException
       
   191      *        Thrown when the buffers cannot be flushed,
       
   192      *        or because the system cannot guarantee that all the
       
   193      *        buffers have been synchronized with physical media.
       
   194      * @since     1.1
       
   195      */
       
   196     public native void sync() throws SyncFailedException;
       
   197 
       
   198     /* This routine initializes JNI field offsets for the class */
       
   199     private static native void initIDs();
       
   200 
       
   201     /**
       
   202      * Set the fd.
       
   203      * If setting to -1, clear the cleaner.
       
   204      * The {@link #registerCleanup()} method should be called for new fds.
       
   205      * @param fd the fd or -1 to indicate closed
       
   206      */
       
   207     @SuppressWarnings("unchecked")
       
   208     synchronized void set(int fd) {
       
   209         if (fd == -1 && cleanup != null) {
       
   210             cleanup.clear();
       
   211             cleanup = null;
       
   212         }
       
   213         this.fd = fd;
       
   214     }
       
   215 
       
   216     /**
       
   217      * Register a cleanup for the current handle.
       
   218      * Used directly in java.io and indirectly via fdAccess.
       
   219      * The cleanup should be registered after the handle is set in the FileDescriptor.
       
   220      */
       
   221     @SuppressWarnings("unchecked")
       
   222     void registerCleanup() {
       
   223         registerCleanup(null);
       
   224     }
       
   225 
       
   226     /**
       
   227      * Register a cleanup for the current handle.
       
   228      * Used directly in java.io and indirectly via fdAccess.
       
   229      * The cleanup should be registered after the handle is set in the FileDescriptor.
       
   230      * @param newCleanable a PhantomCleanable to register
       
   231      */
       
   232     @SuppressWarnings("unchecked")
       
   233     synchronized void registerCleanup(PhantomCleanable<Object> newCleanable) {
       
   234         if (cleanup != null) {
       
   235             cleanup.clear();
       
   236         }
       
   237         cleanup = (newCleanable == null) ? FDCleanup.create(this) : newCleanable;
       
   238     }
       
   239 
       
   240     /**
       
   241      * Unregister a cleanup for the current raw fd.
       
   242      * Used directly in java.io and indirectly via fdAccess.
       
   243      * Normally {@link #close()} should be used except in cases where
       
   244      * it is certain the caller will close the raw fd and the cleanup
       
   245      * must not close the raw fd.  {@link #unregisterCleanup()} must be
       
   246      * called before the raw fd is closed to prevent a race that makes
       
   247      * it possible for the fd to be reallocated to another use and later
       
   248      * the cleanup might be invoked.
       
   249      */
       
   250     synchronized void unregisterCleanup() {
       
   251         if (cleanup != null) {
       
   252             cleanup.clear();
       
   253         }
       
   254         cleanup = null;
       
   255     }
       
   256 
       
   257     /**
       
   258      * Returns true, if the file was opened for appending.
       
   259      */
       
   260     private static native boolean getAppend(int fd);
       
   261 
       
   262     /**
       
   263      * Close the raw file descriptor or handle, if it has not already been closed
       
   264      * and set the fd and handle to -1.
       
   265      * Clear the cleaner so the close does not happen twice.
       
   266      * Package private to allow it to be used in java.io.
       
   267      * @throws IOException if close fails
       
   268      */
       
   269     @SuppressWarnings("unchecked")
       
   270     synchronized void close() throws IOException {
       
   271         if (cleanup != null) {
       
   272             cleanup.clear();
       
   273             cleanup = null;
       
   274         }
       
   275         close0();
       
   276     }
       
   277 
       
   278     /*
       
   279      * Close the raw file descriptor or handle, if it has not already been closed
       
   280      * and set the fd and handle to -1.
       
   281      */
       
   282     private native void close0() throws IOException;
       
   283 
       
   284     /*
       
   285      * Raw close of the file descriptor.
       
   286      * Used only for last chance cleanup.
       
   287      */
       
   288     private static native void cleanupClose0(int fd) throws IOException;
       
   289 
       
   290     /*
       
   291      * Package private methods to track referents.
       
   292      * If multiple streams point to the same FileDescriptor, we cycle
       
   293      * through the list of all referents and call close()
       
   294      */
       
   295 
       
   296     /**
       
   297      * Attach a Closeable to this FD for tracking.
       
   298      * parent reference is added to otherParents when
       
   299      * needed to make closeAll simpler.
       
   300      */
       
   301     synchronized void attach(Closeable c) {
       
   302         if (parent == null) {
       
   303             // first caller gets to do this
       
   304             parent = c;
       
   305         } else if (otherParents == null) {
       
   306             otherParents = new ArrayList<>();
       
   307             otherParents.add(parent);
       
   308             otherParents.add(c);
       
   309         } else {
       
   310             otherParents.add(c);
       
   311         }
       
   312     }
       
   313 
       
   314     /**
       
   315      * Cycle through all Closeables sharing this FD and call
       
   316      * close() on each one.
       
   317      *
       
   318      * The caller closeable gets to call close0().
       
   319      */
       
   320     @SuppressWarnings("try")
       
   321     synchronized void closeAll(Closeable releaser) throws IOException {
       
   322         if (!closed) {
       
   323             closed = true;
       
   324             IOException ioe = null;
       
   325             try (releaser) {
       
   326                 if (otherParents != null) {
       
   327                     for (Closeable referent : otherParents) {
       
   328                         try {
       
   329                             referent.close();
       
   330                         } catch(IOException x) {
       
   331                             if (ioe == null) {
       
   332                                 ioe = x;
       
   333                             } else {
       
   334                                 ioe.addSuppressed(x);
       
   335                             }
       
   336                         }
       
   337                     }
       
   338                 }
       
   339             } catch(IOException ex) {
       
   340                 /*
       
   341                  * If releaser close() throws IOException
       
   342                  * add other exceptions as suppressed.
       
   343                  */
       
   344                 if (ioe != null)
       
   345                     ex.addSuppressed(ioe);
       
   346                 ioe = ex;
       
   347             } finally {
       
   348                 if (ioe != null)
       
   349                     throw ioe;
       
   350             }
       
   351         }
       
   352     }
       
   353 
       
   354     /**
       
   355      * Cleanup for a FileDescriptor when it becomes phantom reachable.
       
   356      * Create a cleanup if fd != -1.
       
   357      * Subclassed from {@code PhantomCleanable} so that {@code clear} can be
       
   358      * called to disable the cleanup when the fd is closed by any means other
       
   359      * than calling {@link FileDescriptor#close}.
       
   360      * Otherwise, it may close the native fd after it has been reused.
       
   361      */
       
   362     static final class FDCleanup extends PhantomCleanable<Object> {
       
   363         private final int fd;
       
   364 
       
   365         static FDCleanup create(FileDescriptor fdo) {
       
   366             return fdo.fd == -1
       
   367                 ? null
       
   368                 : new FDCleanup(fdo, CleanerFactory.cleaner(), fdo.fd);
       
   369         }
       
   370 
       
   371         /**
       
   372          * Constructor for a phantom cleanable reference.
       
   373          * @param obj the object to monitor
       
   374          * @param cleaner the cleaner
       
   375          * @param fd file descriptor to close
       
   376          */
       
   377         private FDCleanup(Object obj, Cleaner cleaner, int fd) {
       
   378             super(obj, cleaner);
       
   379             this.fd = fd;
       
   380         }
       
   381 
       
   382         /**
       
   383          * Close the native fd.
       
   384          */
       
   385         @Override
       
   386         protected void performCleanup() {
       
   387             try {
       
   388                 cleanupClose0(fd);
       
   389             } catch (IOException ioe) {
       
   390                 throw new UncheckedIOException("close", ioe);
       
   391             }
       
   392         }
       
   393     }
       
   394 }