提交 598909bb 编写于 作者: A alanb

6816049: (bf) MappedByteBuffer.force() method does not flush data correctly

Reviewed-by: chegar
上级 4dae3d03
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
package java.nio; package java.nio;
import java.io.FileDescriptor;
import sun.misc.Cleaner; import sun.misc.Cleaner;
import sun.misc.Unsafe; import sun.misc.Unsafe;
import sun.misc.VM; import sun.misc.VM;
...@@ -114,7 +115,7 @@ class Direct$Type$Buffer$RW$$BO$ ...@@ -114,7 +115,7 @@ class Direct$Type$Buffer$RW$$BO$
// //
Direct$Type$Buffer$RW$(int cap) { // package-private Direct$Type$Buffer$RW$(int cap) { // package-private
#if[rw] #if[rw]
super(-1, 0, cap, cap, false); super(-1, 0, cap, cap);
boolean pa = VM.isDirectMemoryPageAligned(); boolean pa = VM.isDirectMemoryPageAligned();
int ps = Bits.pageSize(); int ps = Bits.pageSize();
long size = Math.max(1L, (long)cap + (pa ? ps : 0)); long size = Math.max(1L, (long)cap + (pa ? ps : 0));
...@@ -145,7 +146,7 @@ class Direct$Type$Buffer$RW$$BO$ ...@@ -145,7 +146,7 @@ class Direct$Type$Buffer$RW$$BO$
// Invoked only by JNI: NewDirectByteBuffer(void*, long) // Invoked only by JNI: NewDirectByteBuffer(void*, long)
// //
private Direct$Type$Buffer(long addr, int cap) { private Direct$Type$Buffer(long addr, int cap) {
super(-1, 0, cap, cap, false); super(-1, 0, cap, cap);
address = addr; address = addr;
cleaner = null; cleaner = null;
} }
...@@ -154,14 +155,17 @@ class Direct$Type$Buffer$RW$$BO$ ...@@ -154,14 +155,17 @@ class Direct$Type$Buffer$RW$$BO$
// For memory-mapped buffers -- invoked by FileChannelImpl via reflection // For memory-mapped buffers -- invoked by FileChannelImpl via reflection
// //
protected Direct$Type$Buffer$RW$(int cap, long addr, Runnable unmapper) { protected Direct$Type$Buffer$RW$(int cap, long addr,
FileDescriptor fd,
Runnable unmapper)
{
#if[rw] #if[rw]
super(-1, 0, cap, cap, true); super(-1, 0, cap, cap, fd);
address = addr; address = addr;
viewedBuffer = null; viewedBuffer = null;
cleaner = Cleaner.create(this, unmapper); cleaner = Cleaner.create(this, unmapper);
#else[rw] #else[rw]
super(cap, addr, unmapper); super(cap, addr, fd, unmapper);
#end[rw] #end[rw]
} }
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
package java.nio; package java.nio;
import java.io.FileDescriptor;
import sun.misc.Unsafe; import sun.misc.Unsafe;
...@@ -71,26 +72,26 @@ public abstract class MappedByteBuffer ...@@ -71,26 +72,26 @@ public abstract class MappedByteBuffer
// for optimization purposes, it's easier to do it the other way around. // for optimization purposes, it's easier to do it the other way around.
// This works because DirectByteBuffer is a package-private class. // This works because DirectByteBuffer is a package-private class.
// Volatile to make sure that the finalization thread sees the current // For mapped buffers, a FileDescriptor that may be used for mapping
// value of this so that a region is not accidentally unmapped again later. // operations if valid; null if the buffer is not mapped.
volatile boolean isAMappedBuffer; // package-private private final FileDescriptor fd;
// This should only be invoked by the DirectByteBuffer constructors // This should only be invoked by the DirectByteBuffer constructors
// //
MappedByteBuffer(int mark, int pos, int lim, int cap, // package-private MappedByteBuffer(int mark, int pos, int lim, int cap, // package-private
boolean mapped) FileDescriptor fd)
{ {
super(mark, pos, lim, cap); super(mark, pos, lim, cap);
isAMappedBuffer = mapped; this.fd = fd;
} }
MappedByteBuffer(int mark, int pos, int lim, int cap) { // package-private MappedByteBuffer(int mark, int pos, int lim, int cap) { // package-private
super(mark, pos, lim, cap); super(mark, pos, lim, cap);
isAMappedBuffer = false; this.fd = null;
} }
private void checkMapped() { private void checkMapped() {
if (!isAMappedBuffer) if (fd == null)
// Can only happen if a luser explicitly casts a direct byte buffer // Can only happen if a luser explicitly casts a direct byte buffer
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
...@@ -191,13 +192,12 @@ public abstract class MappedByteBuffer ...@@ -191,13 +192,12 @@ public abstract class MappedByteBuffer
checkMapped(); checkMapped();
if ((address != 0) && (capacity() != 0)) { if ((address != 0) && (capacity() != 0)) {
long offset = mappingOffset(); long offset = mappingOffset();
force0(mappingAddress(offset), mappingLength(offset)); force0(fd, mappingAddress(offset), mappingLength(offset));
} }
return this; return this;
} }
private native boolean isLoaded0(long address, long length, int pageCount); private native boolean isLoaded0(long address, long length, int pageCount);
private native void load0(long address, long length); private native void load0(long address, long length);
private native void force0(long address, long length); private native void force0(FileDescriptor fd, long address, long length);
} }
...@@ -699,15 +699,19 @@ public class FileChannelImpl ...@@ -699,15 +699,19 @@ public class FileChannelImpl
static volatile long totalSize; static volatile long totalSize;
static volatile long totalCapacity; static volatile long totalCapacity;
private long address; private volatile long address;
private long size; private final long size;
private int cap; private final int cap;
private final FileDescriptor fd;
private Unmapper(long address, long size, int cap) { private Unmapper(long address, long size, int cap,
FileDescriptor fd)
{
assert (address != 0); assert (address != 0);
this.address = address; this.address = address;
this.size = size; this.size = size;
this.cap = cap; this.cap = cap;
this.fd = fd;
synchronized (Unmapper.class) { synchronized (Unmapper.class) {
count++; count++;
...@@ -722,6 +726,15 @@ public class FileChannelImpl ...@@ -722,6 +726,15 @@ public class FileChannelImpl
unmap0(address, size); unmap0(address, size);
address = 0; address = 0;
// if this mapping has a valid file descriptor then we close it
if (fd.valid()) {
try {
nd.close(fd);
} catch (IOException ignore) {
// nothing we can do
}
}
synchronized (Unmapper.class) { synchronized (Unmapper.class) {
count--; count--;
totalSize -= size; totalSize -= size;
...@@ -784,10 +797,12 @@ public class FileChannelImpl ...@@ -784,10 +797,12 @@ public class FileChannelImpl
} }
if (size == 0) { if (size == 0) {
addr = 0; addr = 0;
// a valid file descriptor is not required
FileDescriptor dummy = new FileDescriptor();
if ((!writable) || (imode == MAP_RO)) if ((!writable) || (imode == MAP_RO))
return Util.newMappedByteBufferR(0, 0, null); return Util.newMappedByteBufferR(0, 0, dummy, null);
else else
return Util.newMappedByteBuffer(0, 0, null); return Util.newMappedByteBuffer(0, 0, dummy, null);
} }
int pagePosition = (int)(position % allocationGranularity); int pagePosition = (int)(position % allocationGranularity);
...@@ -813,14 +828,31 @@ public class FileChannelImpl ...@@ -813,14 +828,31 @@ public class FileChannelImpl
} }
} }
// On Windows, and potentially other platforms, we need an open
// file descriptor for some mapping operations.
FileDescriptor mfd;
try {
mfd = nd.duplicateForMapping(fd);
} catch (IOException ioe) {
unmap0(addr, mapSize);
throw ioe;
}
assert (IOStatus.checkAll(addr)); assert (IOStatus.checkAll(addr));
assert (addr % allocationGranularity == 0); assert (addr % allocationGranularity == 0);
int isize = (int)size; int isize = (int)size;
Unmapper um = new Unmapper(addr, size + pagePosition, isize); Unmapper um = new Unmapper(addr, mapSize, isize, mfd);
if ((!writable) || (imode == MAP_RO)) if ((!writable) || (imode == MAP_RO)) {
return Util.newMappedByteBufferR(isize, addr + pagePosition, um); return Util.newMappedByteBufferR(isize,
else addr + pagePosition,
return Util.newMappedByteBuffer(isize, addr + pagePosition, um); mfd,
um);
} else {
return Util.newMappedByteBuffer(isize,
addr + pagePosition,
mfd,
um);
}
} finally { } finally {
threads.remove(ti); threads.remove(ti);
end(IOStatus.checkAll(addr)); end(IOStatus.checkAll(addr));
......
...@@ -45,4 +45,12 @@ abstract class FileDispatcher extends NativeDispatcher { ...@@ -45,4 +45,12 @@ abstract class FileDispatcher extends NativeDispatcher {
abstract void release(FileDescriptor fd, long pos, long size) abstract void release(FileDescriptor fd, long pos, long size)
throws IOException; throws IOException;
/**
* Returns a dup of fd if a file descriptor is required for
* memory-mapping operations, otherwise returns an invalid
* FileDescriptor (meaning a newly allocated FileDescriptor)
*/
abstract FileDescriptor duplicateForMapping(FileDescriptor fd)
throws IOException;
} }
...@@ -28,6 +28,7 @@ package sun.nio.ch; ...@@ -28,6 +28,7 @@ package sun.nio.ch;
import java.lang.ref.SoftReference; import java.lang.ref.SoftReference;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.io.IOException; import java.io.IOException;
import java.io.FileDescriptor;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer; import java.nio.MappedByteBuffer;
import java.nio.channels.*; import java.nio.channels.*;
...@@ -364,6 +365,7 @@ class Util { ...@@ -364,6 +365,7 @@ class Util {
Constructor ctor = cl.getDeclaredConstructor( Constructor ctor = cl.getDeclaredConstructor(
new Class[] { int.class, new Class[] { int.class,
long.class, long.class,
FileDescriptor.class,
Runnable.class }); Runnable.class });
ctor.setAccessible(true); ctor.setAccessible(true);
directByteBufferConstructor = ctor; directByteBufferConstructor = ctor;
...@@ -381,6 +383,7 @@ class Util { ...@@ -381,6 +383,7 @@ class Util {
} }
static MappedByteBuffer newMappedByteBuffer(int size, long addr, static MappedByteBuffer newMappedByteBuffer(int size, long addr,
FileDescriptor fd,
Runnable unmapper) Runnable unmapper)
{ {
MappedByteBuffer dbb; MappedByteBuffer dbb;
...@@ -390,6 +393,7 @@ class Util { ...@@ -390,6 +393,7 @@ class Util {
dbb = (MappedByteBuffer)directByteBufferConstructor.newInstance( dbb = (MappedByteBuffer)directByteBufferConstructor.newInstance(
new Object[] { new Integer(size), new Object[] { new Integer(size),
new Long(addr), new Long(addr),
fd,
unmapper }); unmapper });
} catch (InstantiationException e) { } catch (InstantiationException e) {
throw new InternalError(); throw new InternalError();
...@@ -411,6 +415,7 @@ class Util { ...@@ -411,6 +415,7 @@ class Util {
Constructor ctor = cl.getDeclaredConstructor( Constructor ctor = cl.getDeclaredConstructor(
new Class[] { int.class, new Class[] { int.class,
long.class, long.class,
FileDescriptor.class,
Runnable.class }); Runnable.class });
ctor.setAccessible(true); ctor.setAccessible(true);
directByteBufferRConstructor = ctor; directByteBufferRConstructor = ctor;
...@@ -428,6 +433,7 @@ class Util { ...@@ -428,6 +433,7 @@ class Util {
} }
static MappedByteBuffer newMappedByteBufferR(int size, long addr, static MappedByteBuffer newMappedByteBufferR(int size, long addr,
FileDescriptor fd,
Runnable unmapper) Runnable unmapper)
{ {
MappedByteBuffer dbb; MappedByteBuffer dbb;
...@@ -437,6 +443,7 @@ class Util { ...@@ -437,6 +443,7 @@ class Util {
dbb = (MappedByteBuffer)directByteBufferRConstructor.newInstance( dbb = (MappedByteBuffer)directByteBufferRConstructor.newInstance(
new Object[] { new Integer(size), new Object[] { new Integer(size),
new Long(addr), new Long(addr),
fd,
unmapper }); unmapper });
} catch (InstantiationException e) { } catch (InstantiationException e) {
throw new InternalError(); throw new InternalError();
......
...@@ -94,6 +94,12 @@ class FileDispatcherImpl extends FileDispatcher ...@@ -94,6 +94,12 @@ class FileDispatcherImpl extends FileDispatcher
preClose0(fd); preClose0(fd);
} }
FileDescriptor duplicateForMapping(FileDescriptor fd) {
// file descriptor not required for mapping operations; okay
// to return invalid file descriptor.
return new FileDescriptor();
}
// -- Native methods -- // -- Native methods --
static native int read0(FileDescriptor fd, long address, int len) static native int read0(FileDescriptor fd, long address, int len)
......
...@@ -82,8 +82,8 @@ Java_java_nio_MappedByteBuffer_load0(JNIEnv *env, jobject obj, jlong address, ...@@ -82,8 +82,8 @@ Java_java_nio_MappedByteBuffer_load0(JNIEnv *env, jobject obj, jlong address,
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_java_nio_MappedByteBuffer_force0(JNIEnv *env, jobject obj, jlong address, Java_java_nio_MappedByteBuffer_force0(JNIEnv *env, jobject obj, jobject fdo,
jlong len) jlong address, jlong len)
{ {
void* a = (void *)jlong_to_ptr(address); void* a = (void *)jlong_to_ptr(address);
int result = msync(a, (size_t)len, MS_SYNC); int result = msync(a, (size_t)len, MS_SYNC);
......
...@@ -26,10 +26,11 @@ ...@@ -26,10 +26,11 @@
package sun.nio.ch; package sun.nio.ch;
import java.io.*; import java.io.*;
import sun.misc.SharedSecrets;
import sun.misc.JavaIOFileDescriptorAccess;
class FileDispatcherImpl extends FileDispatcher class FileDispatcherImpl extends FileDispatcher
{ {
static { static {
Util.load(); Util.load();
} }
...@@ -94,6 +95,16 @@ class FileDispatcherImpl extends FileDispatcher ...@@ -94,6 +95,16 @@ class FileDispatcherImpl extends FileDispatcher
close0(fd); close0(fd);
} }
FileDescriptor duplicateForMapping(FileDescriptor fd) throws IOException {
// on Windows we need to keep a handle to the file
JavaIOFileDescriptorAccess fdAccess =
SharedSecrets.getJavaIOFileDescriptorAccess();
FileDescriptor result = new FileDescriptor();
long handle = duplicateHandle(fdAccess.getHandle(fd));
fdAccess.setHandle(result, handle);
return result;
}
//-- Native methods //-- Native methods
static native int read0(FileDescriptor fd, long address, int len) static native int read0(FileDescriptor fd, long address, int len)
...@@ -132,4 +143,5 @@ class FileDispatcherImpl extends FileDispatcher ...@@ -132,4 +143,5 @@ class FileDispatcherImpl extends FileDispatcher
static native void closeByHandle(long fd) throws IOException; static native void closeByHandle(long fd) throws IOException;
static native long duplicateHandle(long fd) throws IOException;
} }
...@@ -51,11 +51,11 @@ Java_java_nio_MappedByteBuffer_load0(JNIEnv *env, jobject obj, jlong address, ...@@ -51,11 +51,11 @@ Java_java_nio_MappedByteBuffer_load0(JNIEnv *env, jobject obj, jlong address,
} }
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_java_nio_MappedByteBuffer_force0(JNIEnv *env, jobject obj, jlong address, Java_java_nio_MappedByteBuffer_force0(JNIEnv *env, jobject obj, jobject fdo,
jlong len) jlong address, jlong len)
{ {
void *a = (void *) jlong_to_ptr(address); void *a = (void *) jlong_to_ptr(address);
int result; BOOL result;
int retry; int retry;
/* /*
...@@ -71,6 +71,30 @@ Java_java_nio_MappedByteBuffer_force0(JNIEnv *env, jobject obj, jlong address, ...@@ -71,6 +71,30 @@ Java_java_nio_MappedByteBuffer_force0(JNIEnv *env, jobject obj, jlong address,
retry++; retry++;
} while (retry < 3); } while (retry < 3);
/**
* FlushViewOfFile only initiates the writing of dirty pages to disk
* so we have to call FlushFileBuffers to and ensure they are written.
*/
if (result != 0) {
// by right, the jfieldID initialization should be in a static
// initializer but we do it here instead to avoiding needing to
// load nio.dll during startup.
static jfieldID handle_fdID;
HANDLE h;
if (handle_fdID == NULL) {
jclass clazz = (*env)->FindClass(env, "java/io/FileDescriptor");
if (clazz == NULL)
return; // exception thrown
handle_fdID = (*env)->GetFieldID(env, clazz, "handle", "J");
}
h = jlong_to_ptr((*env)->GetLongField(env, fdo, handle_fdID));
result = FlushFileBuffers(h);
if (result == 0 && GetLastError() == ERROR_ACCESS_DENIED) {
// read-only mapping
result = 1;
}
}
if (result == 0) { if (result == 0) {
JNU_ThrowIOExceptionWithLastError(env, "Flush failed"); JNU_ThrowIOExceptionWithLastError(env, "Flush failed");
} }
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <io.h> #include <io.h>
#include "nio.h" #include "nio.h"
#include "nio_util.h" #include "nio_util.h"
#include "jlong.h"
/************************************************************** /**************************************************************
...@@ -441,3 +442,15 @@ Java_sun_nio_ch_FileDispatcherImpl_closeByHandle(JNIEnv *env, jclass clazz, ...@@ -441,3 +442,15 @@ Java_sun_nio_ch_FileDispatcherImpl_closeByHandle(JNIEnv *env, jclass clazz,
{ {
closeFile(env, fd); closeFile(env, fd);
} }
JNIEXPORT jlong JNICALL
Java_sun_nio_ch_FileDispatcherImpl_duplicateHandle(JNIEnv *env, jclass this, jlong hFile)
{
HANDLE hProcess = GetCurrentProcess();
HANDLE hResult;
BOOL res = DuplicateHandle(hProcess, hFile, hProcess, &hResult, 0, FALSE,
DUPLICATE_SAME_ACCESS);
if (res == 0)
JNU_ThrowIOExceptionWithLastError(env, "DuplicateHandle failed");
return ptr_to_jlong(hResult);
}
...@@ -24,7 +24,6 @@ ...@@ -24,7 +24,6 @@
/* @test /* @test
* @bug 4462336 6799037 * @bug 4462336 6799037
* @summary Simple MappedByteBuffer tests * @summary Simple MappedByteBuffer tests
* @run main/othervm Basic
*/ */
import java.io.*; import java.io.*;
...@@ -76,5 +75,10 @@ public class Basic { ...@@ -76,5 +75,10 @@ public class Basic {
throw new RuntimeException("Incorrect isReadOnly"); throw new RuntimeException("Incorrect isReadOnly");
fc.close(); fc.close();
raf.close(); raf.close();
// clean-up
mbb = null;
System.gc();
Thread.sleep(500);
} }
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册