diff -r 4ebc2e2fb97c -r 71c04702a3d5 src/java.base/unix/classes/java/io/FileDescriptor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.base/unix/classes/java/io/FileDescriptor.java Tue Sep 12 19:03:39 2017 +0200 @@ -0,0 +1,247 @@ +/* + * Copyright (c) 1995, 2015, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package java.io; + +import java.util.ArrayList; +import java.util.List; +import jdk.internal.misc.JavaIOFileDescriptorAccess; +import jdk.internal.misc.SharedSecrets; + +/** + * Instances of the file descriptor class serve as an opaque handle + * to the underlying machine-specific structure representing an open + * file, an open socket, or another source or sink of bytes. The + * main practical use for a file descriptor is to create a + * FileInputStream or FileOutputStream to + * contain it. + *

+ * Applications should not create their own file descriptors. + * + * @author Pavani Diwanji + * @see java.io.FileInputStream + * @see java.io.FileOutputStream + * @since 1.0 + */ +public final class FileDescriptor { + + private int fd; + + private Closeable parent; + private List otherParents; + private boolean closed; + + /** + * true, if file is opened for appending. + */ + private boolean append; + + /** + * Constructs an (invalid) FileDescriptor + * object. + */ + public FileDescriptor() { + fd = -1; + } + + private FileDescriptor(int fd) { + this.fd = fd; + this.append = getAppend(fd); + } + + /** + * A handle to the standard input stream. Usually, this file + * descriptor is not used directly, but rather via the input stream + * known as System.in. + * + * @see java.lang.System#in + */ + public static final FileDescriptor in = new FileDescriptor(0); + + /** + * A handle to the standard output stream. Usually, this file + * descriptor is not used directly, but rather via the output stream + * known as System.out. + * @see java.lang.System#out + */ + public static final FileDescriptor out = new FileDescriptor(1); + + /** + * A handle to the standard error stream. Usually, this file + * descriptor is not used directly, but rather via the output stream + * known as System.err. + * + * @see java.lang.System#err + */ + public static final FileDescriptor err = new FileDescriptor(2); + + /** + * Tests if this file descriptor object is valid. + * + * @return true if the file descriptor object represents a + * valid, open file, socket, or other active I/O connection; + * false otherwise. + */ + public boolean valid() { + return fd != -1; + } + + /** + * Force all system buffers to synchronize with the underlying + * device. This method returns after all modified data and + * attributes of this FileDescriptor have been written to the + * relevant device(s). In particular, if this FileDescriptor + * refers to a physical storage medium, such as a file in a file + * system, sync will not return until all in-memory modified copies + * of buffers associated with this FileDescriptor have been + * written to the physical medium. + * + * sync is meant to be used by code that requires physical + * storage (such as a file) to be in a known state For + * example, a class that provided a simple transaction facility + * might use sync to ensure that all changes to a file caused + * by a given transaction were recorded on a storage medium. + * + * sync only affects buffers downstream of this FileDescriptor. If + * any in-memory buffering is being done by the application (for + * example, by a BufferedOutputStream object), those buffers must + * be flushed into the FileDescriptor (for example, by invoking + * OutputStream.flush) before that data will be affected by sync. + * + * @exception SyncFailedException + * Thrown when the buffers cannot be flushed, + * or because the system cannot guarantee that all the + * buffers have been synchronized with physical media. + * @since 1.1 + */ + public native void sync() throws SyncFailedException; + + /* This routine initializes JNI field offsets for the class */ + private static native void initIDs(); + + static { + initIDs(); + } + + // Set up JavaIOFileDescriptorAccess in SharedSecrets + static { + SharedSecrets.setJavaIOFileDescriptorAccess( + new JavaIOFileDescriptorAccess() { + public void set(FileDescriptor obj, int fd) { + obj.fd = fd; + } + + public int get(FileDescriptor obj) { + return obj.fd; + } + + public void setAppend(FileDescriptor obj, boolean append) { + obj.append = append; + } + + public boolean getAppend(FileDescriptor obj) { + return obj.append; + } + + public void setHandle(FileDescriptor obj, long handle) { + throw new UnsupportedOperationException(); + } + + public long getHandle(FileDescriptor obj) { + throw new UnsupportedOperationException(); + } + } + ); + } + + /** + * Returns true, if the file was opened for appending. + */ + private static native boolean getAppend(int fd); + + /* + * 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() + */ + + /** + * 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); + } + } + + /** + * 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 (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; + } + } + } +}