8080225: FileInput/OutputStream/FileChannel cleanup should be improved

Reviewed-by: mchung, plevart, bpb
This commit is contained in:
Roger Riggs 2017-12-01 16:40:08 -05:00
parent b93586c51e
commit f29e21abb1
23 changed files with 1104 additions and 261 deletions

View file

@ -25,6 +25,7 @@
package java.io;
import java.lang.reflect.Method;
import java.nio.channels.FileChannel;
import sun.nio.ch.FileChannelImpl;
@ -37,6 +38,22 @@ import sun.nio.ch.FileChannelImpl;
* <p><code>FileInputStream</code> is meant for reading streams of raw bytes
* such as image data. For reading streams of characters, consider using
* <code>FileReader</code>.
*
* @apiNote
* To release resources used by this stream {@link #close} should be called
* directly or by try-with-resources. Subclasses are responsible for the cleanup
* of resources acquired by the subclass.
* Subclasses that override {@link #finalize} in order to perform cleanup
* should be modified to use alternative cleanup mechanisms such as
* {@link java.lang.ref.Cleaner} and remove the overriding {@code finalize} method.
*
* @implSpec
* If this FileInputStream has been subclassed and the {@link #close}
* method has been overridden, the {@link #close} method will be
* called when the FileInputStream is unreachable.
* Otherwise, it is implementation specific how the resource cleanup described in
* {@link #close} is performed.
*
* @author Arthur van Hoff
* @see java.io.File
@ -63,6 +80,8 @@ class FileInputStream extends InputStream
private volatile boolean closed;
private final AltFinalizer altFinalizer;
/**
* Creates a <code>FileInputStream</code> by
* opening a connection to an actual file,
@ -137,6 +156,10 @@ class FileInputStream extends InputStream
fd.attach(this);
path = name;
open(name);
altFinalizer = AltFinalizer.get(this);
if (altFinalizer == null) {
fd.registerCleanup(); // open set the fd, register the cleanup
}
}
/**
@ -173,6 +196,7 @@ class FileInputStream extends InputStream
}
fd = fdObj;
path = null;
altFinalizer = null;
/*
* FileDescriptor is being shared by streams.
@ -316,6 +340,14 @@ class FileInputStream extends InputStream
* <p> If this stream has an associated channel then the channel is closed
* as well.
*
* @apiNote
* Overriding {@link #close} to perform cleanup actions is reliable
* only when called directly or when called by try-with-resources.
* Do not depend on finalization to invoke {@code close};
* finalization is not reliable and is deprecated.
* If cleanup of native resources is needed, other mechanisms such as
* {@linkplain java.lang.ref.Cleaner} should be used.
*
* @exception IOException if an I/O error occurs.
*
* @revised 1.4
@ -404,16 +436,27 @@ class FileInputStream extends InputStream
private static native void initIDs();
static {
initIDs();
}
/**
* Ensures that the <code>close</code> method of this file input stream is
* Ensures that the {@link #close} method of this file input stream is
* called when there are no more references to it.
* The {@link #finalize} method does not call {@link #close} directly.
*
* @deprecated The {@code finalize} method has been deprecated.
* @apiNote
* To release resources used by this stream {@link #close} should be called
* directly or by try-with-resources.
*
* @implSpec
* If this FileInputStream has been subclassed and the {@link #close}
* method has been overridden, the {@link #close} method will be
* called when the FileInputStream is unreachable.
* Otherwise, it is implementation specific how the resource cleanup described in
* {@link #close} is performed.
*
* @deprecated The {@code finalize} method has been deprecated and will be removed.
* Subclasses that override {@code finalize} in order to perform cleanup
* should be modified to use alternative cleanup mechanisms and
* to remove the overriding {@code finalize} method.
@ -425,15 +468,57 @@ class FileInputStream extends InputStream
* @exception IOException if an I/O error occurs.
* @see java.io.FileInputStream#close()
*/
@Deprecated(since="9")
@Deprecated(since="9", forRemoval = true)
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()
*/
close();
}
/**
* Class to call {@code FileInputStream.close} when finalized.
* If finalization of the stream is needed, an instance is created
* in its constructor(s). When the set of instances
* related to the stream is unreachable, the AltFinalizer performs
* the needed call to the stream's {@code close} method.
*/
static class AltFinalizer {
private final FileInputStream fis;
/*
* Returns a finalizer object if the FIS needs a finalizer; otherwise null.
* If the FIS has a close method; it needs an AltFinalizer.
*/
static AltFinalizer get(FileInputStream fis) {
Class<?> clazz = fis.getClass();
while (clazz != FileInputStream.class) {
try {
clazz.getDeclaredMethod("close");
return new AltFinalizer(fis);
} catch (NoSuchMethodException nsme) {
// ignore
}
clazz = clazz.getSuperclass();
}
return null;
}
private AltFinalizer(FileInputStream fis) {
this.fis = fis;
}
@Override
@SuppressWarnings("deprecation")
protected final void finalize() {
try {
if ((fis.fd != null) && (fis.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()
*/
fis.close();
}
} catch (IOException ioe) {
// ignore
}
}
}
}

View file

@ -25,6 +25,7 @@
package java.io;
import java.lang.reflect.Method;
import java.nio.channels.FileChannel;
import jdk.internal.misc.SharedSecrets;
import jdk.internal.misc.JavaIOFileDescriptorAccess;
@ -44,6 +45,21 @@ import sun.nio.ch.FileChannelImpl;
* such as image data. For writing streams of characters, consider using
* <code>FileWriter</code>.
*
* @apiNote
* To release resources used by this stream {@link #close} should be called
* directly or by try-with-resources. Subclasses are responsible for the cleanup
* of resources acquired by the subclass.
* Subclasses that override {@link #finalize} in order to perform cleanup
* should be modified to use alternative cleanup mechanisms such as
* {@link java.lang.ref.Cleaner} and remove the overriding {@code finalize} method.
*
* @implSpec
* If this FileOutputStream has been subclassed and the {@link #close}
* method has been overridden, the {@link #close} method will be
* called when the FileInputStream is unreachable.
* Otherwise, it is implementation specific how the resource cleanup described in
* {@link #close} is performed.
*
* @author Arthur van Hoff
* @see java.io.File
* @see java.io.FileDescriptor
@ -80,6 +96,8 @@ class FileOutputStream extends OutputStream
private volatile boolean closed;
private final AltFinalizer altFinalizer;
/**
* Creates a file output stream to write to the file with the
* specified name. A new <code>FileDescriptor</code> object is
@ -218,6 +236,10 @@ class FileOutputStream extends OutputStream
this.path = name;
open(name, append);
altFinalizer = AltFinalizer.get(this);
if (altFinalizer == null) {
fd.registerCleanup(); // open set the fd, register the cleanup
}
}
/**
@ -253,6 +275,7 @@ class FileOutputStream extends OutputStream
}
this.fd = fdObj;
this.path = null;
this.altFinalizer = null;
fd.attach(this);
}
@ -340,6 +363,14 @@ class FileOutputStream extends OutputStream
* <p> If this stream has an associated channel then the channel is closed
* as well.
*
* @apiNote
* Overriding {@link #close} to perform cleanup actions is reliable
* only when called directly or when called by try-with-resources.
* Do not depend on finalization to invoke {@code close};
* finalization is not reliable and is deprecated.
* If cleanup of native resources is needed, other mechanisms such as
* {@linkplain java.lang.ref.Cleaner} should be used.
*
* @exception IOException if an I/O error occurs.
*
* @revised 1.4
@ -429,34 +460,35 @@ class FileOutputStream extends OutputStream
/**
* Cleans up the connection to the file, and ensures that the
* <code>close</code> method of this file output stream is
* {@link #close} method of this file output stream is
* called when there are no more references to this stream.
* The {@link #finalize} method does not call {@link #close} directly.
*
* @apiNote
* To release resources used by this stream {@link #close} should be called
* directly or by try-with-resources.
*
* @implSpec
* If this FileOutputStream has been subclassed and the {@link #close}
* method has been overridden, the {@link #close} method will be
* called when the FileOutputStream is unreachable.
* Otherwise, it is implementation specific how the resource cleanup described in
* {@link #close} is performed.
*
* @deprecated The {@code finalize} method has been deprecated and will be removed.
* Subclasses that override {@code finalize} in order to perform cleanup
* should be modified to use alternative cleanup mechanisms and
* to remove the overriding {@code finalize} method.
* When overriding the {@code finalize} method, its implementation must explicitly
* ensure that {@code super.finalize()} is invoked as described in {@link Object#finalize}.
* See the specification for {@link Object#finalize()} for further
* information about migration options.
*
* @deprecated The {@code finalize} method has been deprecated.
* Subclasses that override {@code finalize} in order to perform cleanup
* should be modified to use alternative cleanup mechanisms and
* to remove the overriding {@code finalize} method.
* When overriding the {@code finalize} method, its implementation must explicitly
* ensure that {@code super.finalize()} is invoked as described in {@link Object#finalize}.
* See the specification for {@link Object#finalize()} for further
* information about migration options.
* @exception IOException if an I/O error occurs.
* @see java.io.FileInputStream#close()
*/
@Deprecated(since="9")
@Deprecated(since="9", forRemoval = true)
protected void finalize() throws IOException {
if (fd != null) {
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()
*/
close();
}
}
}
private static native void initIDs();
@ -465,4 +497,59 @@ class FileOutputStream extends OutputStream
initIDs();
}
/**
* Class to call {@code FileOutputStream.close} when finalized.
* If finalization of the stream is needed, an instance is created
* in its constructor(s). When the set of instances
* related to the stream is unreachable, the AltFinalizer performs
* the needed call to the stream's {@code close} method.
*/
static class AltFinalizer {
private final FileOutputStream fos;
/*
* Returns a finalizer object if the FOS needs a finalizer; otherwise null.
* If the FOS has a close method; it needs an AltFinalizer.
*/
static AltFinalizer get(FileOutputStream fos) {
Class<?> clazz = fos.getClass();
while (clazz != FileOutputStream.class) {
try {
clazz.getDeclaredMethod("close");
return new AltFinalizer(fos);
} catch (NoSuchMethodException nsme) {
// ignore
}
clazz = clazz.getSuperclass();
}
return null;
}
private AltFinalizer(FileOutputStream fos) {
this.fos = fos;
}
@Override
@SuppressWarnings("deprecation")
protected final void finalize() {
try {
if (fos.fd != null) {
if (fos.fd == FileDescriptor.out || fos.fd == FileDescriptor.err) {
// Subclass may override flush; otherwise it is no-op
fos.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()
*/
fos.close();
}
}
} catch (IOException ioe) {
// ignore
}
}
}
}

View file

@ -257,6 +257,7 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable {
fd.attach(this);
path = name;
open(name, imode);
fd.registerCleanup(); // open sets the fd, register the cleanup
}
/**

View file

@ -283,7 +283,7 @@ class SocketInputStream extends FileInputStream
/**
* Overrides finalize, the fd is closed by the Socket.
*/
@SuppressWarnings("deprecation")
@SuppressWarnings({"deprecation", "removal"})
protected void finalize() {}
/**

View file

@ -175,7 +175,7 @@ class SocketOutputStream extends FileOutputStream
/**
* Overrides finalize, the fd is closed by the Socket.
*/
@SuppressWarnings("deprecation")
@SuppressWarnings({"deprecation", "removal"})
protected void finalize() {}
/**

View file

@ -25,6 +25,7 @@
package jdk.internal.misc;
import java.io.FileDescriptor;
import java.io.IOException;
/*
* @author Chris Hegarty
@ -35,7 +36,8 @@ public interface JavaIOFileDescriptorAccess {
public int get(FileDescriptor fdo);
public void setAppend(FileDescriptor fdo, boolean append);
public boolean getAppend(FileDescriptor fdo);
public void close(FileDescriptor fdo);
public void close(FileDescriptor fdo) throws IOException;
public void registerCleanup(FileDescriptor fdo);
// Only valid on Windows
public void setHandle(FileDescriptor fdo, long handle);

View file

@ -27,6 +27,7 @@ package sun.nio.ch;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.lang.ref.Cleaner.Cleanable;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
@ -109,7 +110,12 @@ public class FileChannelImpl
}
public void run() {
fdAccess.close(fd);
try {
fdAccess.close(fd);
} catch (IOException ioe) {
// Rethrow as unchecked so the exception can be propagated as needed
throw new UncheckedIOException("close", ioe);
}
}
}
@ -188,7 +194,11 @@ public class FileChannelImpl
} else if (closer != null) {
// Perform the cleaning action so it is not redone when
// this channel becomes phantom reachable.
closer.clean();
try {
closer.clean();
} catch (UncheckedIOException uioe) {
throw uioe.getCause();
}
} else {
fdAccess.close(fd);
}

View file

@ -25,10 +25,14 @@
package java.io;
import java.lang.ref.Cleaner;
import java.util.ArrayList;
import java.util.List;
import jdk.internal.misc.JavaIOFileDescriptorAccess;
import jdk.internal.misc.SharedSecrets;
import jdk.internal.ref.CleanerFactory;
import jdk.internal.ref.PhantomCleanable;
/**
* Instances of the file descriptor class serve as an opaque handle
@ -64,7 +68,7 @@ public final class FileDescriptor {
SharedSecrets.setJavaIOFileDescriptorAccess(
new JavaIOFileDescriptorAccess() {
public void set(FileDescriptor fdo, int fd) {
fdo.fd = fd;
fdo.set(fd);
}
public int get(FileDescriptor fdo) {
@ -79,10 +83,14 @@ public final class FileDescriptor {
return fdo.append;
}
public void close(FileDescriptor fdo) {
public void close(FileDescriptor fdo) throws IOException {
fdo.close();
}
public void registerCleanup(FileDescriptor fdo) {
fdo.registerCleanup();
}
public void setHandle(FileDescriptor fdo, long handle) {
throw new UnsupportedOperationException();
}
@ -94,6 +102,11 @@ public final class FileDescriptor {
);
}
/**
* Cleanup in case FileDescriptor is not explicitly closed.
*/
private FDCleanup cleanup;
/**
* Constructs an (invalid) FileDescriptor
* object.
@ -177,6 +190,34 @@ public final class FileDescriptor {
/* This routine initializes JNI field offsets for the class */
private static native void initIDs();
/**
* Set the fd.
* If setting to -1, clear the cleaner.
* The {@link #registerCleanup()} method should be called for new fds.
* @param fd the fd or -1 to indicate closed
*/
@SuppressWarnings("unchecked")
synchronized void set(int fd) {
if (fd == -1 && cleanup != null) {
cleanup.clear();
cleanup = null;
}
this.fd = fd;
}
/**
* Register a cleanup for the current raw fd.
* Used directly in java.io and indirectly via fdAccess.
* The cleanup should be registered after the fd is set in the FileDescriptor.
*/
@SuppressWarnings("unchecked")
synchronized void registerCleanup() {
if (cleanup != null) {
cleanup.clear();
}
cleanup = FDCleanup.create(this);
}
/**
* Returns true, if the file was opened for appending.
*/
@ -185,9 +226,30 @@ public final class FileDescriptor {
/**
* Close the raw file descriptor or handle, if it has not already been closed
* and set the fd and handle to -1.
* Clear the cleaner so the close does not happen twice.
* Package private to allow it to be used in java.io.
* @throws IOException if close fails
*/
native void close();
@SuppressWarnings("unchecked")
synchronized void close() throws IOException {
if (cleanup != null) {
cleanup.clear();
cleanup = null;
}
close0();
}
/*
* Close the raw file descriptor or handle, if it has not already been closed
* and set the fd and handle to -1.
*/
private native void close0() throws IOException;
/*
* Raw close of the file descriptor.
* Used only for last chance cleanup.
*/
private static native void cleanupClose0(int fd) throws IOException;
/*
* Package private methods to track referents.
@ -252,4 +314,45 @@ public final class FileDescriptor {
}
}
}
/**
* Cleanup for a FileDescriptor when it becomes phantom reachable.
* Create a cleanup if fd != -1.
* Subclassed from {@code PhantomCleanable} so that {@code clear} can be
* called to disable the cleanup when the fd is closed by any means other
* than calling {@link FileDescriptor#close}.
* Otherwise, it may close the native fd after it has been reused.
*/
static final class FDCleanup extends PhantomCleanable<Object> {
private final int fd;
static FDCleanup create(FileDescriptor fdo) {
return fdo.fd == -1
? null
: new FDCleanup(fdo, CleanerFactory.cleaner(), fdo.fd);
}
/**
* Constructor for a phantom cleanable reference.
* @param obj the object to monitor
* @param cleaner the cleaner
* @param fd file descriptor to close
*/
private FDCleanup(Object obj, Cleaner cleaner, int fd) {
super(obj, cleaner);
this.fd = fd;
}
/**
* Close the native fd.
*/
@Override
protected void performCleanup() {
try {
cleanupClose0(fd);
} catch (IOException ioe) {
throw new UncheckedIOException("close", ioe);
}
}
}
}

View file

@ -71,8 +71,17 @@ Java_java_io_FileDescriptor_getAppend(JNIEnv *env, jclass fdClass, jint fd) {
return ((flags & O_APPEND) == 0) ? JNI_FALSE : JNI_TRUE;
}
JNIEXPORT void JNICALL
Java_java_io_FileDescriptor_cleanupClose0(JNIEnv *env, jclass fdClass, jint fd) {
if (fd != -1) {
if (close(fd) == -1) {
JNU_ThrowIOExceptionWithLastError(env, "close failed");
}
}
}
// instance method close0 for FileDescriptor
JNIEXPORT void JNICALL
Java_java_io_FileDescriptor_close(JNIEnv *env, jobject this) {
Java_java_io_FileDescriptor_close0(JNIEnv *env, jobject this) {
fileDescriptorClose(env, this);
}

View file

@ -139,6 +139,11 @@ fileDescriptorClose(JNIEnv *env, jobject this)
if ((*env)->ExceptionOccurred(env)) {
return;
}
if (fd == -1) {
return; // already closed and set to -1
}
/* Set the fd to -1 before closing it so that the timing window
* of other threads using the wrong fd (closed but recycled fd,
* that gets re-opened with some other filename) is reduced.

View file

@ -25,10 +25,14 @@
package java.io;
import java.lang.ref.Cleaner;
import java.util.ArrayList;
import java.util.List;
import jdk.internal.misc.JavaIOFileDescriptorAccess;
import jdk.internal.misc.SharedSecrets;
import jdk.internal.ref.CleanerFactory;
import jdk.internal.ref.PhantomCleanable;
/**
* Instances of the file descriptor class serve as an opaque handle
@ -81,12 +85,16 @@ public final class FileDescriptor {
return fdo.append;
}
public void close(FileDescriptor fdo) {
public void close(FileDescriptor fdo) throws IOException {
fdo.close();
}
public void registerCleanup(FileDescriptor fdo) {
fdo.registerCleanup();
}
public void setHandle(FileDescriptor fdo, long handle) {
fdo.handle = handle;
fdo.setHandle(handle);
}
public long getHandle(FileDescriptor fdo) {
@ -96,6 +104,11 @@ public final class FileDescriptor {
);
}
/**
* Cleanup in case FileDescriptor is not explicitly closed.
*/
private FDCleanup cleanup;
/**
* Constructs an (invalid) FileDescriptor
* object.
@ -149,7 +162,7 @@ public final class FileDescriptor {
* 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 FileDesecriptor have been
* of buffers associated with this FileDescriptor have been
* written to the physical medium.
*
* sync is meant to be used by code that requires physical
@ -175,20 +188,69 @@ public final class FileDescriptor {
/* This routine initializes JNI field offsets for the class */
private static native void initIDs();
private static native long set(int d);
private static FileDescriptor standardStream(int fd) {
FileDescriptor desc = new FileDescriptor();
desc.handle = set(fd);
desc.handle = getHandle(fd);
return desc;
}
private static native long getHandle(int d);
/**
* Set the handle.
* If setting to -1, clear the cleaner.
* The {@link #registerCleanup()} method should be called for new handles.
* @param handle the handle or -1 to indicate closed
*/
@SuppressWarnings("unchecked")
void setHandle(long handle) {
if (handle == -1 && cleanup != null) {
cleanup.clear();
cleanup = null;
}
this.handle = handle;
}
/**
* Register a cleanup for the current handle.
* Used directly in java.io and indirectly via fdAccess.
* The cleanup should be registered after the handle is set in the FileDescriptor.
*/
@SuppressWarnings("unchecked")
synchronized void registerCleanup() {
if (cleanup != null) {
cleanup.clear();
}
cleanup = FDCleanup.create(this);
}
/**
* Close the raw file descriptor or handle, if it has not already been closed
* and set the fd and handle to -1.
* Clear the cleaner so the close does not happen twice.
* Package private to allow it to be used in java.io.
* @throws IOException if close fails
*/
native void close();
@SuppressWarnings("unchecked")
synchronized void close() throws IOException {
if (cleanup != null) {
cleanup.clear();
cleanup = null;
}
close0();
}
/*
* Close the raw file descriptor or handle, if it has not already been closed
* and set the fd and handle to -1.
*/
private native void close0() throws IOException;
/*
* Raw close of the file handle.
* Used only for last chance cleanup.
*/
private static native void cleanupClose0(long handle) throws IOException;
/*
* Package private methods to track referents.
@ -253,4 +315,45 @@ public final class FileDescriptor {
}
}
}
/**
* Cleanup for a FileDescriptor when it becomes phantom reachable.
* Create a cleanup if handle != -1.
* Subclassed from {@code PhantomCleanable} so that {@code clear} can be
* called to disable the cleanup when the fd is closed by any means other
* than calling {@link FileDescriptor#close}.
* Otherwise, it may close the handle after it has been reused.
*/
static final class FDCleanup extends PhantomCleanable<Object> {
private final long handle;
static FDCleanup create(FileDescriptor fdo) {
return fdo.handle == -1
? null
: new FDCleanup(fdo, CleanerFactory.cleaner(), fdo.handle);
}
/**
* Constructor for a phantom cleanable reference.
* @param obj the object to monitor
* @param cleaner the cleaner
* @param handle file handle to close
*/
private FDCleanup(Object obj, Cleaner cleaner, long handle) {
super(obj, cleaner);
this.handle = handle;
}
/**
* Close the native handle.
*/
@Override
protected void performCleanup() {
try {
cleanupClose0(handle);
} catch (IOException ioe) {
throw new UncheckedIOException("close", ioe);
}
}
}
}

View file

@ -114,6 +114,7 @@ class FileDispatcherImpl extends FileDispatcher {
FileDescriptor result = new FileDescriptor();
long handle = duplicateHandle(fdAccess.getHandle(fd));
fdAccess.setHandle(result, handle);
fdAccess.registerCleanup(result);
return result;
}

View file

@ -139,7 +139,7 @@ public class WindowsAsynchronousFileChannelImpl
invalidateAllLocks();
// close the file
close0(handle);
nd.close(fdObj);
// waits until all I/O operations have completed
ioCache.close();
@ -728,8 +728,6 @@ public class WindowsAsynchronousFileChannelImpl
private static native int lockFile(long handle, long position, long size,
boolean shared, long overlapped) throws IOException;
private static native void close0(long handle);
static {
IOUtil.load();
}

View file

@ -216,8 +216,7 @@ class WindowsChannelFactory {
} catch (IOException x) {
// IOException is thrown if the file handle cannot be associated
// with the completion port. All we can do is close the file.
long handle = fdAccess.getHandle(fdObj);
CloseHandle(handle);
fdAccess.close(fdObj);
throw x;
}
}
@ -347,6 +346,7 @@ class WindowsChannelFactory {
FileDescriptor fdObj = new FileDescriptor();
fdAccess.setHandle(fdObj, handle);
fdAccess.setAppend(fdObj, flags.append);
fdAccess.registerCleanup(fdObj);
return fdObj;
}
}

View file

@ -57,7 +57,7 @@ Java_java_io_FileDescriptor_initIDs(JNIEnv *env, jclass fdClass) {
}
JNIEXPORT jlong JNICALL
Java_java_io_FileDescriptor_set(JNIEnv *env, jclass fdClass, jint fd) {
Java_java_io_FileDescriptor_getHandle(JNIEnv *env, jclass fdClass, jint fd) {
SET_HANDLE(fd);
}
@ -73,8 +73,17 @@ Java_java_io_FileDescriptor_sync(JNIEnv *env, jobject this) {
}
}
JNIEXPORT void JNICALL
Java_java_io_FileDescriptor_cleanupClose0(JNIEnv *env, jclass fdClass, jlong handle) {
if (handle != -1) {
if (CloseHandle((HANDLE)handle) == -1) {
JNU_ThrowIOExceptionWithLastError(env, "close failed");
}
}
}
// instance method close0 for FileDescriptor
JNIEXPORT void JNICALL
Java_java_io_FileDescriptor_close(JNIEnv *env, jobject this) {
Java_java_io_FileDescriptor_close0(JNIEnv *env, jobject this) {
fileDescriptorClose(env, this);
}

View file

@ -121,13 +121,3 @@ Java_sun_nio_ch_WindowsAsynchronousFileChannelImpl_lockFile(JNIEnv *env, jobject
return 0;
}
JNIEXPORT void JNICALL
Java_sun_nio_ch_WindowsAsynchronousFileChannelImpl_close0(JNIEnv* env, jclass this,
jlong handle)
{
HANDLE h = (HANDLE)jlong_to_ptr(handle);
BOOL result = CloseHandle(h);
if (result == 0) {
JNU_ThrowIOExceptionWithLastError(env, "Close failed");
}
}