Merge
This commit is contained in:
commit
d576d9a662
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -138,8 +138,23 @@ public abstract class Reference<T> {
|
|||||||
pending = r.discovered;
|
pending = r.discovered;
|
||||||
r.discovered = null;
|
r.discovered = null;
|
||||||
} else {
|
} else {
|
||||||
|
// The waiting on the lock may cause an OOME because it may try to allocate
|
||||||
|
// exception objects, so also catch OOME here to avoid silent exit of the
|
||||||
|
// reference handler thread.
|
||||||
|
//
|
||||||
|
// Explicitly define the order of the two exceptions we catch here
|
||||||
|
// when waiting for the lock.
|
||||||
|
//
|
||||||
|
// We do not want to try to potentially load the InterruptedException class
|
||||||
|
// (which would be done if this was its first use, and InterruptedException
|
||||||
|
// were checked first) in this situation.
|
||||||
|
//
|
||||||
|
// This may lead to the VM not ever trying to load the InterruptedException
|
||||||
|
// class again.
|
||||||
|
try {
|
||||||
try {
|
try {
|
||||||
lock.wait();
|
lock.wait();
|
||||||
|
} catch (OutOfMemoryError x) { }
|
||||||
} catch (InterruptedException x) { }
|
} catch (InterruptedException x) { }
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -100,6 +100,7 @@ class WindowsConstants {
|
|||||||
public static final int ERROR_INVALID_LEVEL = 124;
|
public static final int ERROR_INVALID_LEVEL = 124;
|
||||||
public static final int ERROR_DIR_NOT_EMPTY = 145;
|
public static final int ERROR_DIR_NOT_EMPTY = 145;
|
||||||
public static final int ERROR_ALREADY_EXISTS = 183;
|
public static final int ERROR_ALREADY_EXISTS = 183;
|
||||||
|
public static final int ERROR_MORE_DATA = 234;
|
||||||
public static final int ERROR_DIRECTORY = 267;
|
public static final int ERROR_DIRECTORY = 267;
|
||||||
public static final int ERROR_NOTIFY_ENUM_DIR = 1022;
|
public static final int ERROR_NOTIFY_ENUM_DIR = 1022;
|
||||||
public static final int ERROR_NONE_MAPPED = 1332;
|
public static final int ERROR_NONE_MAPPED = 1332;
|
||||||
|
@ -973,19 +973,19 @@ class WindowsNativeDispatcher {
|
|||||||
* HANDLE CreateIoCompletionPort (
|
* HANDLE CreateIoCompletionPort (
|
||||||
* HANDLE FileHandle,
|
* HANDLE FileHandle,
|
||||||
* HANDLE ExistingCompletionPort,
|
* HANDLE ExistingCompletionPort,
|
||||||
* DWORD CompletionKey,
|
* ULONG_PTR CompletionKey,
|
||||||
* DWORD NumberOfConcurrentThreads
|
* DWORD NumberOfConcurrentThreads
|
||||||
* )
|
* )
|
||||||
*/
|
*/
|
||||||
static native long CreateIoCompletionPort(long fileHandle, long existingPort,
|
static native long CreateIoCompletionPort(long fileHandle, long existingPort,
|
||||||
int completionKey) throws WindowsException;
|
long completionKey) throws WindowsException;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GetQueuedCompletionStatus(
|
* GetQueuedCompletionStatus(
|
||||||
* HANDLE CompletionPort,
|
* HANDLE CompletionPort,
|
||||||
* LPDWORD lpNumberOfBytesTransferred,
|
* LPDWORD lpNumberOfBytesTransferred,
|
||||||
* LPDWORD lpCompletionKey,
|
* PULONG_PTR lpCompletionKey,
|
||||||
* LPOVERLAPPED *lpOverlapped,
|
* LPOVERLAPPED *lpOverlapped,
|
||||||
* DWORD dwMilliseconds
|
* DWORD dwMilliseconds
|
||||||
*/
|
*/
|
||||||
@ -999,12 +999,12 @@ class WindowsNativeDispatcher {
|
|||||||
static class CompletionStatus {
|
static class CompletionStatus {
|
||||||
private int error;
|
private int error;
|
||||||
private int bytesTransferred;
|
private int bytesTransferred;
|
||||||
private int completionKey;
|
private long completionKey;
|
||||||
private CompletionStatus() { }
|
private CompletionStatus() { }
|
||||||
|
|
||||||
int error() { return error; }
|
int error() { return error; }
|
||||||
int bytesTransferred() { return bytesTransferred; }
|
int bytesTransferred() { return bytesTransferred; }
|
||||||
int completionKey() { return completionKey; }
|
long completionKey() { return completionKey; }
|
||||||
}
|
}
|
||||||
private static native void GetQueuedCompletionStatus0(long completionPort,
|
private static native void GetQueuedCompletionStatus0(long completionPort,
|
||||||
CompletionStatus status) throws WindowsException;
|
CompletionStatus status) throws WindowsException;
|
||||||
@ -1013,12 +1013,12 @@ class WindowsNativeDispatcher {
|
|||||||
* PostQueuedCompletionStatus(
|
* PostQueuedCompletionStatus(
|
||||||
* HANDLE CompletionPort,
|
* HANDLE CompletionPort,
|
||||||
* DWORD dwNumberOfBytesTransferred,
|
* DWORD dwNumberOfBytesTransferred,
|
||||||
* DWORD dwCompletionKey,
|
* ULONG_PTR dwCompletionKey,
|
||||||
* LPOVERLAPPED lpOverlapped
|
* LPOVERLAPPED lpOverlapped
|
||||||
* )
|
* )
|
||||||
*/
|
*/
|
||||||
static native void PostQueuedCompletionStatus(long completionPort,
|
static native void PostQueuedCompletionStatus(long completionPort,
|
||||||
int completionKey) throws WindowsException;
|
long completionKey) throws WindowsException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ReadDirectoryChangesW(
|
* ReadDirectoryChangesW(
|
||||||
|
@ -41,6 +41,7 @@ import static sun.nio.fs.WindowsConstants.*;
|
|||||||
class WindowsWatchService
|
class WindowsWatchService
|
||||||
extends AbstractWatchService
|
extends AbstractWatchService
|
||||||
{
|
{
|
||||||
|
private final static int WAKEUP_COMPLETION_KEY = 0;
|
||||||
private final Unsafe unsafe = Unsafe.getUnsafe();
|
private final Unsafe unsafe = Unsafe.getUnsafe();
|
||||||
|
|
||||||
// background thread to service I/O completion port
|
// background thread to service I/O completion port
|
||||||
@ -83,7 +84,7 @@ class WindowsWatchService
|
|||||||
*/
|
*/
|
||||||
private class WindowsWatchKey extends AbstractWatchKey {
|
private class WindowsWatchKey extends AbstractWatchKey {
|
||||||
// file key (used to detect existing registrations)
|
// file key (used to detect existing registrations)
|
||||||
private FileKey fileKey;
|
private final FileKey fileKey;
|
||||||
|
|
||||||
// handle to directory
|
// handle to directory
|
||||||
private volatile long handle = INVALID_HANDLE_VALUE;
|
private volatile long handle = INVALID_HANDLE_VALUE;
|
||||||
@ -223,8 +224,7 @@ class WindowsWatchService
|
|||||||
FileKey other = (FileKey)obj;
|
FileKey other = (FileKey)obj;
|
||||||
if (this.volSerialNumber != other.volSerialNumber) return false;
|
if (this.volSerialNumber != other.volSerialNumber) return false;
|
||||||
if (this.fileIndexHigh != other.fileIndexHigh) return false;
|
if (this.fileIndexHigh != other.fileIndexHigh) return false;
|
||||||
if (this.fileIndexLow != other.fileIndexLow) return false;
|
return this.fileIndexLow == other.fileIndexLow;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,6 +268,7 @@ class WindowsWatchService
|
|||||||
private static final short OFFSETOF_FILENAME = 12;
|
private static final short OFFSETOF_FILENAME = 12;
|
||||||
|
|
||||||
// size of per-directory buffer for events (FIXME - make this configurable)
|
// size of per-directory buffer for events (FIXME - make this configurable)
|
||||||
|
// Need to be less than 4*16384 = 65536. DWORD align.
|
||||||
private static final int CHANGES_BUFFER_SIZE = 16 * 1024;
|
private static final int CHANGES_BUFFER_SIZE = 16 * 1024;
|
||||||
|
|
||||||
private final WindowsFileSystem fs;
|
private final WindowsFileSystem fs;
|
||||||
@ -275,27 +276,28 @@ class WindowsWatchService
|
|||||||
private final long port;
|
private final long port;
|
||||||
|
|
||||||
// maps completion key to WatchKey
|
// maps completion key to WatchKey
|
||||||
private final Map<Integer,WindowsWatchKey> int2key;
|
private final Map<Integer,WindowsWatchKey> ck2key;
|
||||||
|
|
||||||
// maps file key to WatchKey
|
// maps file key to WatchKey
|
||||||
private final Map<FileKey,WindowsWatchKey> fk2key;
|
private final Map<FileKey,WindowsWatchKey> fk2key;
|
||||||
|
|
||||||
// unique completion key for each directory
|
// unique completion key for each directory
|
||||||
|
// native completion key capacity is 64 bits on Win64.
|
||||||
private int lastCompletionKey;
|
private int lastCompletionKey;
|
||||||
|
|
||||||
Poller(WindowsFileSystem fs, WindowsWatchService watcher, long port) {
|
Poller(WindowsFileSystem fs, WindowsWatchService watcher, long port) {
|
||||||
this.fs = fs;
|
this.fs = fs;
|
||||||
this.watcher = watcher;
|
this.watcher = watcher;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.int2key = new HashMap<Integer,WindowsWatchKey>();
|
this.ck2key = new HashMap<>();
|
||||||
this.fk2key = new HashMap<FileKey,WindowsWatchKey>();
|
this.fk2key = new HashMap<>();
|
||||||
this.lastCompletionKey = 0;
|
this.lastCompletionKey = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void wakeup() throws IOException {
|
void wakeup() throws IOException {
|
||||||
try {
|
try {
|
||||||
PostQueuedCompletionStatus(port, 0);
|
PostQueuedCompletionStatus(port, WAKEUP_COMPLETION_KEY);
|
||||||
} catch (WindowsException x) {
|
} catch (WindowsException x) {
|
||||||
throw new IOException(x.getMessage());
|
throw new IOException(x.getMessage());
|
||||||
}
|
}
|
||||||
@ -322,7 +324,6 @@ class WindowsWatchService
|
|||||||
for (WatchEvent.Modifier modifier: modifiers) {
|
for (WatchEvent.Modifier modifier: modifiers) {
|
||||||
if (modifier == ExtendedWatchEventModifier.FILE_TREE) {
|
if (modifier == ExtendedWatchEventModifier.FILE_TREE) {
|
||||||
watchSubtree = true;
|
watchSubtree = true;
|
||||||
continue;
|
|
||||||
} else {
|
} else {
|
||||||
if (modifier == null)
|
if (modifier == null)
|
||||||
return new NullPointerException();
|
return new NullPointerException();
|
||||||
@ -333,7 +334,7 @@ class WindowsWatchService
|
|||||||
}
|
}
|
||||||
|
|
||||||
// open directory
|
// open directory
|
||||||
long handle = -1L;
|
long handle;
|
||||||
try {
|
try {
|
||||||
handle = CreateFile(dir.getPathForWin32Calls(),
|
handle = CreateFile(dir.getPathForWin32Calls(),
|
||||||
FILE_LIST_DIRECTORY,
|
FILE_LIST_DIRECTORY,
|
||||||
@ -347,7 +348,7 @@ class WindowsWatchService
|
|||||||
boolean registered = false;
|
boolean registered = false;
|
||||||
try {
|
try {
|
||||||
// read attributes and check file is a directory
|
// read attributes and check file is a directory
|
||||||
WindowsFileAttributes attrs = null;
|
WindowsFileAttributes attrs;
|
||||||
try {
|
try {
|
||||||
attrs = WindowsFileAttributes.readAttributes(handle);
|
attrs = WindowsFileAttributes.readAttributes(handle);
|
||||||
} catch (WindowsException x) {
|
} catch (WindowsException x) {
|
||||||
@ -370,9 +371,10 @@ class WindowsWatchService
|
|||||||
return existing;
|
return existing;
|
||||||
}
|
}
|
||||||
|
|
||||||
// unique completion key (skip 0)
|
// Can overflow the int type capacity.
|
||||||
|
// Skip WAKEUP_COMPLETION_KEY value.
|
||||||
int completionKey = ++lastCompletionKey;
|
int completionKey = ++lastCompletionKey;
|
||||||
if (completionKey == 0)
|
if (completionKey == WAKEUP_COMPLETION_KEY)
|
||||||
completionKey = ++lastCompletionKey;
|
completionKey = ++lastCompletionKey;
|
||||||
|
|
||||||
// associate handle with completion port
|
// associate handle with completion port
|
||||||
@ -418,13 +420,13 @@ class WindowsWatchService
|
|||||||
// 1. remove mapping from old completion key to existing watch key
|
// 1. remove mapping from old completion key to existing watch key
|
||||||
// 2. release existing key's resources (handle/buffer)
|
// 2. release existing key's resources (handle/buffer)
|
||||||
// 3. re-initialize key with new handle/buffer
|
// 3. re-initialize key with new handle/buffer
|
||||||
int2key.remove(existing.completionKey());
|
ck2key.remove(existing.completionKey());
|
||||||
existing.releaseResources();
|
existing.releaseResources();
|
||||||
watchKey = existing.init(handle, events, watchSubtree, buffer,
|
watchKey = existing.init(handle, events, watchSubtree, buffer,
|
||||||
countAddress, overlappedAddress, completionKey);
|
countAddress, overlappedAddress, completionKey);
|
||||||
}
|
}
|
||||||
// map completion map to watch key
|
// map completion map to watch key
|
||||||
int2key.put(completionKey, watchKey);
|
ck2key.put(completionKey, watchKey);
|
||||||
|
|
||||||
registered = true;
|
registered = true;
|
||||||
return watchKey;
|
return watchKey;
|
||||||
@ -440,7 +442,7 @@ class WindowsWatchService
|
|||||||
WindowsWatchKey key = (WindowsWatchKey)obj;
|
WindowsWatchKey key = (WindowsWatchKey)obj;
|
||||||
if (key.isValid()) {
|
if (key.isValid()) {
|
||||||
fk2key.remove(key.fileKey());
|
fk2key.remove(key.fileKey());
|
||||||
int2key.remove(key.completionKey());
|
ck2key.remove(key.completionKey());
|
||||||
key.invalidate();
|
key.invalidate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -449,11 +451,11 @@ class WindowsWatchService
|
|||||||
@Override
|
@Override
|
||||||
void implCloseAll() {
|
void implCloseAll() {
|
||||||
// cancel all keys
|
// cancel all keys
|
||||||
for (Map.Entry<Integer,WindowsWatchKey> entry: int2key.entrySet()) {
|
for (Map.Entry<Integer, WindowsWatchKey> entry: ck2key.entrySet()) {
|
||||||
entry.getValue().invalidate();
|
entry.getValue().invalidate();
|
||||||
}
|
}
|
||||||
fk2key.clear();
|
fk2key.clear();
|
||||||
int2key.clear();
|
ck2key.clear();
|
||||||
|
|
||||||
// close I/O completion port
|
// close I/O completion port
|
||||||
CloseHandle(port);
|
CloseHandle(port);
|
||||||
@ -517,7 +519,7 @@ class WindowsWatchService
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
CompletionStatus info = null;
|
CompletionStatus info;
|
||||||
try {
|
try {
|
||||||
info = GetQueuedCompletionStatus(port);
|
info = GetQueuedCompletionStatus(port);
|
||||||
} catch (WindowsException x) {
|
} catch (WindowsException x) {
|
||||||
@ -527,7 +529,7 @@ class WindowsWatchService
|
|||||||
}
|
}
|
||||||
|
|
||||||
// wakeup
|
// wakeup
|
||||||
if (info.completionKey() == 0) {
|
if (info.completionKey() == WAKEUP_COMPLETION_KEY) {
|
||||||
boolean shutdown = processRequests();
|
boolean shutdown = processRequests();
|
||||||
if (shutdown) {
|
if (shutdown) {
|
||||||
return;
|
return;
|
||||||
@ -536,7 +538,7 @@ class WindowsWatchService
|
|||||||
}
|
}
|
||||||
|
|
||||||
// map completionKey to get WatchKey
|
// map completionKey to get WatchKey
|
||||||
WindowsWatchKey key = int2key.get(info.completionKey());
|
WindowsWatchKey key = ck2key.get((int)info.completionKey());
|
||||||
if (key == null) {
|
if (key == null) {
|
||||||
// We get here when a registration is changed. In that case
|
// We get here when a registration is changed. In that case
|
||||||
// the directory is closed which causes an event with the
|
// the directory is closed which causes an event with the
|
||||||
@ -544,24 +546,26 @@ class WindowsWatchService
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadDirectoryChangesW failed
|
boolean criticalError = false;
|
||||||
if (info.error() != 0) {
|
int errorCode = info.error();
|
||||||
|
int messageSize = info.bytesTransferred();
|
||||||
|
if (errorCode == ERROR_NOTIFY_ENUM_DIR) {
|
||||||
// buffer overflow
|
// buffer overflow
|
||||||
if (info.error() == ERROR_NOTIFY_ENUM_DIR) {
|
|
||||||
key.signalEvent(StandardWatchEventKinds.OVERFLOW, null);
|
key.signalEvent(StandardWatchEventKinds.OVERFLOW, null);
|
||||||
|
} else if (errorCode != 0 && errorCode != ERROR_MORE_DATA) {
|
||||||
|
// ReadDirectoryChangesW failed
|
||||||
|
criticalError = true;
|
||||||
} else {
|
} else {
|
||||||
// other error so cancel key
|
// ERROR_MORE_DATA is a warning about incomplite
|
||||||
implCancelKey(key);
|
// data transfer over TCP/UDP stack. For the case
|
||||||
key.signal();
|
// [messageSize] is zero in the most of cases.
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// process the events
|
if (messageSize > 0) {
|
||||||
if (info.bytesTransferred() > 0) {
|
// process non-empty events.
|
||||||
processEvents(key, info.bytesTransferred());
|
processEvents(key, messageSize);
|
||||||
} else {
|
} else if (errorCode == 0) {
|
||||||
// insufficient buffer size
|
// insufficient buffer size
|
||||||
|
// not described, but can happen.
|
||||||
key.signalEvent(StandardWatchEventKinds.OVERFLOW, null);
|
key.signalEvent(StandardWatchEventKinds.OVERFLOW, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -576,6 +580,10 @@ class WindowsWatchService
|
|||||||
key.overlappedAddress());
|
key.overlappedAddress());
|
||||||
} catch (WindowsException x) {
|
} catch (WindowsException x) {
|
||||||
// no choice but to cancel key
|
// no choice but to cancel key
|
||||||
|
criticalError = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (criticalError) {
|
||||||
implCancelKey(key);
|
implCancelKey(key);
|
||||||
key.signal();
|
key.signal();
|
||||||
}
|
}
|
||||||
|
@ -162,7 +162,7 @@ Java_sun_nio_fs_WindowsNativeDispatcher_initIDs(JNIEnv* env, jclass this)
|
|||||||
}
|
}
|
||||||
completionStatus_error = (*env)->GetFieldID(env, clazz, "error", "I");
|
completionStatus_error = (*env)->GetFieldID(env, clazz, "error", "I");
|
||||||
completionStatus_bytesTransferred = (*env)->GetFieldID(env, clazz, "bytesTransferred", "I");
|
completionStatus_bytesTransferred = (*env)->GetFieldID(env, clazz, "bytesTransferred", "I");
|
||||||
completionStatus_completionKey = (*env)->GetFieldID(env, clazz, "completionKey", "I");
|
completionStatus_completionKey = (*env)->GetFieldID(env, clazz, "completionKey", "J");
|
||||||
|
|
||||||
clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$BackupResult");
|
clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$BackupResult");
|
||||||
if (clazz == NULL) {
|
if (clazz == NULL) {
|
||||||
@ -1169,12 +1169,11 @@ Java_sun_nio_fs_WindowsNativeDispatcher_GetFinalPathNameByHandle(JNIEnv* env,
|
|||||||
|
|
||||||
JNIEXPORT jlong JNICALL
|
JNIEXPORT jlong JNICALL
|
||||||
Java_sun_nio_fs_WindowsNativeDispatcher_CreateIoCompletionPort(JNIEnv* env, jclass this,
|
Java_sun_nio_fs_WindowsNativeDispatcher_CreateIoCompletionPort(JNIEnv* env, jclass this,
|
||||||
jlong fileHandle, jlong existingPort, jint completionKey)
|
jlong fileHandle, jlong existingPort, jlong completionKey)
|
||||||
{
|
{
|
||||||
ULONG_PTR ck = completionKey;
|
|
||||||
HANDLE port = CreateIoCompletionPort((HANDLE)jlong_to_ptr(fileHandle),
|
HANDLE port = CreateIoCompletionPort((HANDLE)jlong_to_ptr(fileHandle),
|
||||||
(HANDLE)jlong_to_ptr(existingPort),
|
(HANDLE)jlong_to_ptr(existingPort),
|
||||||
ck,
|
(ULONG_PTR)completionKey,
|
||||||
0);
|
0);
|
||||||
if (port == NULL) {
|
if (port == NULL) {
|
||||||
throwWindowsException(env, GetLastError());
|
throwWindowsException(env, GetLastError());
|
||||||
@ -1203,21 +1202,20 @@ Java_sun_nio_fs_WindowsNativeDispatcher_GetQueuedCompletionStatus0(JNIEnv* env,
|
|||||||
(*env)->SetIntField(env, obj, completionStatus_error, ioResult);
|
(*env)->SetIntField(env, obj, completionStatus_error, ioResult);
|
||||||
(*env)->SetIntField(env, obj, completionStatus_bytesTransferred,
|
(*env)->SetIntField(env, obj, completionStatus_bytesTransferred,
|
||||||
(jint)bytesTransferred);
|
(jint)bytesTransferred);
|
||||||
(*env)->SetIntField(env, obj, completionStatus_completionKey,
|
(*env)->SetLongField(env, obj, completionStatus_completionKey,
|
||||||
(jint)completionKey);
|
(jlong)completionKey);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
Java_sun_nio_fs_WindowsNativeDispatcher_PostQueuedCompletionStatus(JNIEnv* env, jclass this,
|
Java_sun_nio_fs_WindowsNativeDispatcher_PostQueuedCompletionStatus(JNIEnv* env, jclass this,
|
||||||
jlong completionPort, jint completionKey)
|
jlong completionPort, jlong completionKey)
|
||||||
{
|
{
|
||||||
BOOL res;
|
BOOL res;
|
||||||
|
|
||||||
res = PostQueuedCompletionStatus((HANDLE)jlong_to_ptr(completionPort),
|
res = PostQueuedCompletionStatus((HANDLE)jlong_to_ptr(completionPort),
|
||||||
(DWORD)0, /* dwNumberOfBytesTransferred */
|
(DWORD)0, /* dwNumberOfBytesTransferred */
|
||||||
(DWORD)completionKey,
|
(ULONG_PTR)completionKey,
|
||||||
NULL); /* lpOverlapped */
|
NULL); /* lpOverlapped */
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
throwWindowsException(env, GetLastError());
|
throwWindowsException(env, GetLastError());
|
||||||
@ -1232,7 +1230,17 @@ Java_sun_nio_fs_WindowsNativeDispatcher_ReadDirectoryChangesW(JNIEnv* env, jclas
|
|||||||
BOOL res;
|
BOOL res;
|
||||||
BOOL subtree = (watchSubTree == JNI_TRUE) ? TRUE : FALSE;
|
BOOL subtree = (watchSubTree == JNI_TRUE) ? TRUE : FALSE;
|
||||||
|
|
||||||
((LPOVERLAPPED)jlong_to_ptr(pOverlapped))->hEvent = NULL;
|
/* Any unused members of [OVERLAPPED] structure should always be initialized to zero
|
||||||
|
before the structure is used in a function call.
|
||||||
|
Otherwise, the function may fail and return ERROR_INVALID_PARAMETER.
|
||||||
|
http://msdn.microsoft.com/en-us/library/windows/desktop/ms684342%28v=vs.85%29.aspx
|
||||||
|
|
||||||
|
The [Offset] and [OffsetHigh] members of this structure are not used.
|
||||||
|
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465%28v=vs.85%29.aspx
|
||||||
|
|
||||||
|
[hEvent] should be zero, other fields are the return values. */
|
||||||
|
ZeroMemory((LPOVERLAPPED)jlong_to_ptr(pOverlapped), sizeof(OVERLAPPED));
|
||||||
|
|
||||||
res = ReadDirectoryChangesW((HANDLE)jlong_to_ptr(hDirectory),
|
res = ReadDirectoryChangesW((HANDLE)jlong_to_ptr(hDirectory),
|
||||||
(LPVOID)jlong_to_ptr(bufferAddress),
|
(LPVOID)jlong_to_ptr(bufferAddress),
|
||||||
(DWORD)bufferLength,
|
(DWORD)bufferLength,
|
||||||
|
112
jdk/test/java/lang/ref/OOMEInReferenceHandler.java
Normal file
112
jdk/test/java/lang/ref/OOMEInReferenceHandler.java
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2013, 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @bug 7038914
|
||||||
|
* @summary Verify that the reference handler does not die after an OOME allocating the InterruptedException object
|
||||||
|
* @run main/othervm -Xmx16M -XX:-UseTLAB OOMEInReferenceHandler
|
||||||
|
* @author peter.levart@gmail.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.lang.ref.*;
|
||||||
|
|
||||||
|
public class OOMEInReferenceHandler {
|
||||||
|
static Object[] fillHeap() {
|
||||||
|
Object[] first = null, last = null;
|
||||||
|
int size = 1 << 20;
|
||||||
|
while (size > 0) {
|
||||||
|
try {
|
||||||
|
Object[] array = new Object[size];
|
||||||
|
if (first == null) {
|
||||||
|
first = array;
|
||||||
|
} else {
|
||||||
|
last[0] = array;
|
||||||
|
}
|
||||||
|
last = array;
|
||||||
|
} catch (OutOfMemoryError oome) {
|
||||||
|
size = size >>> 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
// preinitialize the InterruptedException class so that the reference handler
|
||||||
|
// does not die due to OOME when loading the class if it is the first use
|
||||||
|
InterruptedException ie = new InterruptedException("dummy");
|
||||||
|
|
||||||
|
ThreadGroup tg = Thread.currentThread().getThreadGroup();
|
||||||
|
for (
|
||||||
|
ThreadGroup tgn = tg;
|
||||||
|
tgn != null;
|
||||||
|
tg = tgn, tgn = tg.getParent()
|
||||||
|
)
|
||||||
|
;
|
||||||
|
|
||||||
|
Thread[] threads = new Thread[tg.activeCount()];
|
||||||
|
Thread referenceHandlerThread = null;
|
||||||
|
int n = tg.enumerate(threads);
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
if ("Reference Handler".equals(threads[i].getName())) {
|
||||||
|
referenceHandlerThread = threads[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (referenceHandlerThread == null) {
|
||||||
|
throw new IllegalStateException("Couldn't find Reference Handler thread.");
|
||||||
|
}
|
||||||
|
|
||||||
|
ReferenceQueue<Object> refQueue = new ReferenceQueue<>();
|
||||||
|
Object referent = new Object();
|
||||||
|
WeakReference<Object> weakRef = new WeakReference<>(referent, refQueue);
|
||||||
|
|
||||||
|
Object waste = fillHeap();
|
||||||
|
|
||||||
|
referenceHandlerThread.interrupt();
|
||||||
|
|
||||||
|
// allow referenceHandlerThread some time to throw OOME
|
||||||
|
Thread.sleep(500L);
|
||||||
|
|
||||||
|
// release waste & referent
|
||||||
|
waste = null;
|
||||||
|
referent = null;
|
||||||
|
|
||||||
|
// wait at most 10 seconds for success or failure
|
||||||
|
for (int i = 0; i < 20; i++) {
|
||||||
|
if (refQueue.poll() != null) {
|
||||||
|
// Reference Handler thread still working -> success
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
System.gc();
|
||||||
|
Thread.sleep(500L); // wait a little to allow GC to do it's work before allocating objects
|
||||||
|
if (!referenceHandlerThread.isAlive()) {
|
||||||
|
// Reference Handler thread died -> failure
|
||||||
|
throw new Exception("Reference Handler thread died.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no sure answer after 10 seconds
|
||||||
|
throw new IllegalStateException("Reference Handler thread stuck.");
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user