Path: blob/master/src/java.base/share/classes/java/io/FileDescriptor.java
41152 views
/*1* Copyright (c) 2003, 2019, 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. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.io;2627import java.util.ArrayList;28import java.util.List;29import java.util.Objects;3031import jdk.internal.access.JavaIOFileDescriptorAccess;32import jdk.internal.access.SharedSecrets;33import jdk.internal.ref.PhantomCleanable;3435/**36* Instances of the file descriptor class serve as an opaque handle37* to the underlying machine-specific structure representing an open38* file, an open socket, or another source or sink of bytes.39* The main practical use for a file descriptor is to create a40* {@link FileInputStream} or {@link FileOutputStream} to contain it.41* <p>42* Applications should not create their own file descriptors.43*44* @author Pavani Diwanji45* @since 1.046*/47public final class FileDescriptor {4849private int fd;5051private long handle;5253private Closeable parent;54private List<Closeable> otherParents;55private boolean closed;5657/**58* true, if file is opened for appending.59*/60private boolean append;6162static {63initIDs();64}6566// Set up JavaIOFileDescriptorAccess in SharedSecrets67static {68SharedSecrets.setJavaIOFileDescriptorAccess(69new JavaIOFileDescriptorAccess() {70public void set(FileDescriptor fdo, int fd) {71fdo.set(fd);72}7374public int get(FileDescriptor fdo) {75return fdo.fd;76}7778public void setAppend(FileDescriptor fdo, boolean append) {79fdo.append = append;80}8182public boolean getAppend(FileDescriptor fdo) {83return fdo.append;84}8586public void close(FileDescriptor fdo) throws IOException {87fdo.close();88}8990/* Register for a normal FileCleanable fd/handle cleanup. */91public void registerCleanup(FileDescriptor fdo) {92FileCleanable.register(fdo);93}9495/* Register a custom PhantomCleanup. */96public void registerCleanup(FileDescriptor fdo,97PhantomCleanable<FileDescriptor> cleanup) {98fdo.registerCleanup(cleanup);99}100101public void unregisterCleanup(FileDescriptor fdo) {102fdo.unregisterCleanup();103}104105public void setHandle(FileDescriptor fdo, long handle) {106fdo.setHandle(handle);107}108109public long getHandle(FileDescriptor fdo) {110return fdo.handle;111}112}113);114}115116/**117* Cleanup in case FileDescriptor is not explicitly closed.118*/119private PhantomCleanable<FileDescriptor> cleanup;120121/**122* Constructs an (invalid) FileDescriptor object.123* The fd or handle is set later.124*/125public FileDescriptor() {126fd = -1;127handle = -1;128}129130/**131* Used for standard input, output, and error only.132* For Windows the corresponding handle is initialized.133* For Unix the append mode is cached.134* @param fd the raw fd number (0, 1, 2)135*/136private FileDescriptor(int fd) {137this.fd = fd;138this.handle = getHandle(fd);139this.append = getAppend(fd);140}141142/**143* A handle to the standard input stream. Usually, this file144* descriptor is not used directly, but rather via the input stream145* known as {@code System.in}.146*147* @see java.lang.System#in148*/149public static final FileDescriptor in = new FileDescriptor(0);150151/**152* A handle to the standard output stream. Usually, this file153* descriptor is not used directly, but rather via the output stream154* known as {@code System.out}.155* @see java.lang.System#out156*/157public static final FileDescriptor out = new FileDescriptor(1);158159/**160* A handle to the standard error stream. Usually, this file161* descriptor is not used directly, but rather via the output stream162* known as {@code System.err}.163*164* @see java.lang.System#err165*/166public static final FileDescriptor err = new FileDescriptor(2);167168/**169* Tests if this file descriptor object is valid.170*171* @return {@code true} if the file descriptor object represents a172* valid, open file, socket, or other active I/O connection;173* {@code false} otherwise.174*/175public boolean valid() {176return (handle != -1) || (fd != -1);177}178179/**180* Force all system buffers to synchronize with the underlying181* device. This method returns after all modified data and182* attributes of this FileDescriptor have been written to the183* relevant device(s). In particular, if this FileDescriptor184* refers to a physical storage medium, such as a file in a file185* system, sync will not return until all in-memory modified copies186* of buffers associated with this FileDescriptor have been187* written to the physical medium.188*189* sync is meant to be used by code that requires physical190* storage (such as a file) to be in a known state For191* example, a class that provided a simple transaction facility192* might use sync to ensure that all changes to a file caused193* by a given transaction were recorded on a storage medium.194*195* sync only affects buffers downstream of this FileDescriptor. If196* any in-memory buffering is being done by the application (for197* example, by a BufferedOutputStream object), those buffers must198* be flushed into the FileDescriptor (for example, by invoking199* OutputStream.flush) before that data will be affected by sync.200*201* @throws SyncFailedException202* Thrown when the buffers cannot be flushed,203* or because the system cannot guarantee that all the204* buffers have been synchronized with physical media.205* @since 1.1206*/207public native void sync() throws SyncFailedException;208209/* This routine initializes JNI field offsets for the class */210private static native void initIDs();211212/*213* On Windows return the handle for the standard streams.214*/215private static native long getHandle(int d);216217/**218* Returns true, if the file was opened for appending.219*/220private static native boolean getAppend(int fd);221222/**223* Set the fd.224* Used on Unix and for sockets on Windows and Unix.225* If setting to -1, clear the cleaner.226* The {@link #registerCleanup} method should be called for new fds.227* @param fd the raw fd or -1 to indicate closed228*/229@SuppressWarnings("unchecked")230synchronized void set(int fd) {231if (fd == -1 && cleanup != null) {232cleanup.clear();233cleanup = null;234}235this.fd = fd;236}237238/**239* Set the handle.240* Used on Windows for regular files.241* If setting to -1, clear the cleaner.242* The {@link #registerCleanup} method should be called for new handles.243* @param handle the handle or -1 to indicate closed244*/245@SuppressWarnings("unchecked")246void setHandle(long handle) {247if (handle == -1 && cleanup != null) {248cleanup.clear();249cleanup = null;250}251this.handle = handle;252}253254/**255* Register a cleanup for the current handle.256* Used directly in java.io and indirectly via fdAccess.257* The cleanup should be registered after the handle is set in the FileDescriptor.258* @param cleanable a PhantomCleanable to register259*/260@SuppressWarnings("unchecked")261synchronized void registerCleanup(PhantomCleanable<FileDescriptor> cleanable) {262Objects.requireNonNull(cleanable, "cleanable");263if (cleanup != null) {264cleanup.clear();265}266cleanup = cleanable;267}268269/**270* Unregister a cleanup for the current raw fd or handle.271* Used directly in java.io and indirectly via fdAccess.272* Normally {@link #close()} should be used except in cases where273* it is certain the caller will close the raw fd and the cleanup274* must not close the raw fd. {@link #unregisterCleanup()} must be275* called before the raw fd is closed to prevent a race that makes276* it possible for the fd to be reallocated to another use and later277* the cleanup might be invoked.278*/279synchronized void unregisterCleanup() {280if (cleanup != null) {281cleanup.clear();282}283cleanup = null;284}285286/**287* Close the raw file descriptor or handle, if it has not already been closed.288* The native code sets the fd and handle to -1.289* Clear the cleaner so the close does not happen twice.290* Package private to allow it to be used in java.io.291* @throws IOException if close fails292*/293@SuppressWarnings("unchecked")294synchronized void close() throws IOException {295unregisterCleanup();296close0();297}298299/*300* Close the raw file descriptor or handle, if it has not already been closed301* and set the fd and handle to -1.302*/303private native void close0() throws IOException;304305/*306* Package private methods to track referents.307* If multiple streams point to the same FileDescriptor, we cycle308* through the list of all referents and call close()309*/310311/**312* Attach a Closeable to this FD for tracking.313* parent reference is added to otherParents when314* needed to make closeAll simpler.315*/316synchronized void attach(Closeable c) {317if (parent == null) {318// first caller gets to do this319parent = c;320} else if (otherParents == null) {321otherParents = new ArrayList<>();322otherParents.add(parent);323otherParents.add(c);324} else {325otherParents.add(c);326}327}328329/**330* Cycle through all Closeables sharing this FD and call331* close() on each one.332*333* The caller closeable gets to call close0().334*/335@SuppressWarnings("try")336synchronized void closeAll(Closeable releaser) throws IOException {337if (!closed) {338closed = true;339IOException ioe = null;340try (releaser) {341if (otherParents != null) {342for (Closeable referent : otherParents) {343try {344referent.close();345} catch(IOException x) {346if (ioe == null) {347ioe = x;348} else {349ioe.addSuppressed(x);350}351}352}353}354} catch(IOException ex) {355/*356* If releaser close() throws IOException357* add other exceptions as suppressed.358*/359if (ioe != null)360ex.addSuppressed(ioe);361ioe = ex;362} finally {363if (ioe != null)364throw ioe;365}366}367}368}369370371