mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-24 04:54:40 +02:00
8187443: Forest Consolidation: Move files to unified layout
Reviewed-by: darcy, ihse
This commit is contained in:
parent
270fe13182
commit
3789983e89
56923 changed files with 3 additions and 15727 deletions
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright (c) 2001, 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. 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 sun.nio.ch;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
|
||||
/**
|
||||
* Allows different platforms to call different native methods
|
||||
* for read and write operations.
|
||||
*/
|
||||
|
||||
class DatagramDispatcher extends NativeDispatcher
|
||||
{
|
||||
static {
|
||||
IOUtil.load();
|
||||
}
|
||||
|
||||
int read(FileDescriptor fd, long address, int len) throws IOException {
|
||||
return read0(fd, address, len);
|
||||
}
|
||||
|
||||
long readv(FileDescriptor fd, long address, int len) throws IOException {
|
||||
return readv0(fd, address, len);
|
||||
}
|
||||
|
||||
int write(FileDescriptor fd, long address, int len) throws IOException {
|
||||
return write0(fd, address, len);
|
||||
}
|
||||
|
||||
long writev(FileDescriptor fd, long address, int len) throws IOException {
|
||||
return writev0(fd, address, len);
|
||||
}
|
||||
|
||||
void close(FileDescriptor fd) throws IOException {
|
||||
SocketDispatcher.close0(fd);
|
||||
}
|
||||
|
||||
static native int read0(FileDescriptor fd, long address, int len)
|
||||
throws IOException;
|
||||
|
||||
static native long readv0(FileDescriptor fd, long address, int len)
|
||||
throws IOException;
|
||||
|
||||
static native int write0(FileDescriptor fd, long address, int len)
|
||||
throws IOException;
|
||||
|
||||
static native long writev0(FileDescriptor fd, long address, int len)
|
||||
throws IOException;
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2009, 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 sun.nio.ch;
|
||||
|
||||
import java.nio.channels.spi.AsynchronousChannelProvider;
|
||||
|
||||
/**
|
||||
* Creates this platform's default asynchronous channel provider
|
||||
*/
|
||||
|
||||
public class DefaultAsynchronousChannelProvider {
|
||||
private DefaultAsynchronousChannelProvider() { }
|
||||
|
||||
/**
|
||||
* Returns the default AsynchronousChannelProvider.
|
||||
*/
|
||||
public static AsynchronousChannelProvider create() {
|
||||
return new WindowsAsynchronousChannelProvider();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2001, 2002, 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 sun.nio.ch;
|
||||
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
|
||||
|
||||
/**
|
||||
* Creates this platform's default SelectorProvider
|
||||
*/
|
||||
|
||||
public class DefaultSelectorProvider {
|
||||
|
||||
/**
|
||||
* Prevent instantiation.
|
||||
*/
|
||||
private DefaultSelectorProvider() { }
|
||||
|
||||
/**
|
||||
* Returns the default SelectorProvider.
|
||||
*/
|
||||
public static SelectorProvider create() {
|
||||
return new sun.nio.ch.WindowsSelectorProvider();
|
||||
}
|
||||
|
||||
}
|
180
src/java.base/windows/classes/sun/nio/ch/FileDispatcherImpl.java
Normal file
180
src/java.base/windows/classes/sun/nio/ch/FileDispatcherImpl.java
Normal file
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2017, 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 sun.nio.ch;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import jdk.internal.misc.JavaIOFileDescriptorAccess;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
class FileDispatcherImpl extends FileDispatcher {
|
||||
|
||||
private static final JavaIOFileDescriptorAccess fdAccess =
|
||||
SharedSecrets.getJavaIOFileDescriptorAccess();
|
||||
|
||||
// set to true if fast file transmission (TransmitFile) is enabled
|
||||
private static final boolean fastFileTransfer;
|
||||
|
||||
FileDispatcherImpl() { }
|
||||
|
||||
@Override
|
||||
boolean needsPositionLock() {
|
||||
return true;
|
||||
}
|
||||
|
||||
int read(FileDescriptor fd, long address, int len)
|
||||
throws IOException
|
||||
{
|
||||
return read0(fd, address, len);
|
||||
}
|
||||
|
||||
int pread(FileDescriptor fd, long address, int len, long position)
|
||||
throws IOException
|
||||
{
|
||||
return pread0(fd, address, len, position);
|
||||
}
|
||||
|
||||
long readv(FileDescriptor fd, long address, int len) throws IOException {
|
||||
return readv0(fd, address, len);
|
||||
}
|
||||
|
||||
int write(FileDescriptor fd, long address, int len) throws IOException {
|
||||
return write0(fd, address, len, fdAccess.getAppend(fd));
|
||||
}
|
||||
|
||||
int pwrite(FileDescriptor fd, long address, int len, long position)
|
||||
throws IOException
|
||||
{
|
||||
return pwrite0(fd, address, len, position);
|
||||
}
|
||||
|
||||
long writev(FileDescriptor fd, long address, int len) throws IOException {
|
||||
return writev0(fd, address, len, fdAccess.getAppend(fd));
|
||||
}
|
||||
|
||||
int force(FileDescriptor fd, boolean metaData) throws IOException {
|
||||
return force0(fd, metaData);
|
||||
}
|
||||
|
||||
int truncate(FileDescriptor fd, long size) throws IOException {
|
||||
return truncate0(fd, size);
|
||||
}
|
||||
|
||||
int allocate(FileDescriptor fd, long size) throws IOException {
|
||||
// truncate0() works for extending and truncating file size
|
||||
return truncate0(fd, size);
|
||||
}
|
||||
|
||||
long size(FileDescriptor fd) throws IOException {
|
||||
return size0(fd);
|
||||
}
|
||||
|
||||
int lock(FileDescriptor fd, boolean blocking, long pos, long size,
|
||||
boolean shared) throws IOException
|
||||
{
|
||||
return lock0(fd, blocking, pos, size, shared);
|
||||
}
|
||||
|
||||
void release(FileDescriptor fd, long pos, long size) throws IOException {
|
||||
release0(fd, pos, size);
|
||||
}
|
||||
|
||||
void close(FileDescriptor fd) throws IOException {
|
||||
close0(fd);
|
||||
}
|
||||
|
||||
FileDescriptor duplicateForMapping(FileDescriptor fd) throws IOException {
|
||||
// on Windows we need to keep a handle to the file
|
||||
FileDescriptor result = new FileDescriptor();
|
||||
long handle = duplicateHandle(fdAccess.getHandle(fd));
|
||||
fdAccess.setHandle(result, handle);
|
||||
return result;
|
||||
}
|
||||
|
||||
boolean canTransferToDirectly(java.nio.channels.SelectableChannel sc) {
|
||||
return fastFileTransfer && sc.isBlocking();
|
||||
}
|
||||
|
||||
boolean transferToDirectlyNeedsPositionLock() {
|
||||
return true;
|
||||
}
|
||||
|
||||
static boolean isFastFileTransferRequested() {
|
||||
String fileTransferProp = GetPropertyAction
|
||||
.privilegedGetProperty("jdk.nio.enableFastFileTransfer");
|
||||
boolean enable;
|
||||
if ("".equals(fileTransferProp)) {
|
||||
enable = true;
|
||||
} else {
|
||||
enable = Boolean.parseBoolean(fileTransferProp);
|
||||
}
|
||||
return enable;
|
||||
}
|
||||
|
||||
static {
|
||||
IOUtil.load();
|
||||
fastFileTransfer = isFastFileTransferRequested();
|
||||
}
|
||||
|
||||
//-- Native methods
|
||||
|
||||
static native int read0(FileDescriptor fd, long address, int len)
|
||||
throws IOException;
|
||||
|
||||
static native int pread0(FileDescriptor fd, long address, int len,
|
||||
long position) throws IOException;
|
||||
|
||||
static native long readv0(FileDescriptor fd, long address, int len)
|
||||
throws IOException;
|
||||
|
||||
static native int write0(FileDescriptor fd, long address, int len, boolean append)
|
||||
throws IOException;
|
||||
|
||||
static native int pwrite0(FileDescriptor fd, long address, int len,
|
||||
long position) throws IOException;
|
||||
|
||||
static native long writev0(FileDescriptor fd, long address, int len, boolean append)
|
||||
throws IOException;
|
||||
|
||||
static native int force0(FileDescriptor fd, boolean metaData)
|
||||
throws IOException;
|
||||
|
||||
static native int truncate0(FileDescriptor fd, long size)
|
||||
throws IOException;
|
||||
|
||||
static native long size0(FileDescriptor fd) throws IOException;
|
||||
|
||||
static native int lock0(FileDescriptor fd, boolean blocking, long pos,
|
||||
long size, boolean shared) throws IOException;
|
||||
|
||||
static native void release0(FileDescriptor fd, long pos, long size)
|
||||
throws IOException;
|
||||
|
||||
static native void close0(FileDescriptor fd) throws IOException;
|
||||
|
||||
static native long duplicateHandle(long fd) throws IOException;
|
||||
}
|
75
src/java.base/windows/classes/sun/nio/ch/FileKey.java
Normal file
75
src/java.base/windows/classes/sun/nio/ch/FileKey.java
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 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. 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 sun.nio.ch;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
|
||||
/*
|
||||
* Represents a key to a specific file on Windows
|
||||
*/
|
||||
public class FileKey {
|
||||
|
||||
private long dwVolumeSerialNumber;
|
||||
private long nFileIndexHigh;
|
||||
private long nFileIndexLow;
|
||||
|
||||
private FileKey() { }
|
||||
|
||||
public static FileKey create(FileDescriptor fd) throws IOException {
|
||||
FileKey fk = new FileKey();
|
||||
fk.init(fd);
|
||||
return fk;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return (int)(dwVolumeSerialNumber ^ (dwVolumeSerialNumber >>> 32)) +
|
||||
(int)(nFileIndexHigh ^ (nFileIndexHigh >>> 32)) +
|
||||
(int)(nFileIndexLow ^ (nFileIndexHigh >>> 32));
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this)
|
||||
return true;
|
||||
if (!(obj instanceof FileKey))
|
||||
return false;
|
||||
FileKey other = (FileKey)obj;
|
||||
if ((this.dwVolumeSerialNumber != other.dwVolumeSerialNumber) ||
|
||||
(this.nFileIndexHigh != other.nFileIndexHigh) ||
|
||||
(this.nFileIndexLow != other.nFileIndexLow)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private native void init(FileDescriptor fd) throws IOException;
|
||||
private static native void initIDs();
|
||||
|
||||
static {
|
||||
IOUtil.load();
|
||||
initIDs();
|
||||
}
|
||||
}
|
439
src/java.base/windows/classes/sun/nio/ch/Iocp.java
Normal file
439
src/java.base/windows/classes/sun/nio/ch/Iocp.java
Normal file
|
@ -0,0 +1,439 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 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. 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 sun.nio.ch;
|
||||
|
||||
import java.nio.channels.*;
|
||||
import java.nio.channels.spi.AsynchronousChannelProvider;
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.io.FileDescriptor;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
/**
|
||||
* Windows implementation of AsynchronousChannelGroup encapsulating an I/O
|
||||
* completion port.
|
||||
*/
|
||||
|
||||
class Iocp extends AsynchronousChannelGroupImpl {
|
||||
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||
private static final long INVALID_HANDLE_VALUE = -1L;
|
||||
|
||||
// maps completion key to channel
|
||||
private final ReadWriteLock keyToChannelLock = new ReentrantReadWriteLock();
|
||||
private final Map<Integer,OverlappedChannel> keyToChannel =
|
||||
new HashMap<Integer,OverlappedChannel>();
|
||||
private int nextCompletionKey;
|
||||
|
||||
// handle to completion port
|
||||
private final long port;
|
||||
|
||||
// true if port has been closed
|
||||
private boolean closed;
|
||||
|
||||
// the set of "stale" OVERLAPPED structures. These OVERLAPPED structures
|
||||
// relate to I/O operations where the completion notification was not
|
||||
// received in a timely manner after the channel is closed.
|
||||
private final Set<Long> staleIoSet = new HashSet<Long>();
|
||||
|
||||
Iocp(AsynchronousChannelProvider provider, ThreadPool pool)
|
||||
throws IOException
|
||||
{
|
||||
super(provider, pool);
|
||||
this.port =
|
||||
createIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, fixedThreadCount());
|
||||
this.nextCompletionKey = 1;
|
||||
}
|
||||
|
||||
Iocp start() {
|
||||
startThreads(new EventHandlerTask());
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* Channels implements this interface support overlapped I/O and can be
|
||||
* associated with a completion port.
|
||||
*/
|
||||
static interface OverlappedChannel extends Closeable {
|
||||
/**
|
||||
* Returns a reference to the pending I/O result.
|
||||
*/
|
||||
<V,A> PendingFuture<V,A> getByOverlapped(long overlapped);
|
||||
}
|
||||
|
||||
// release all resources
|
||||
void implClose() {
|
||||
synchronized (this) {
|
||||
if (closed)
|
||||
return;
|
||||
closed = true;
|
||||
}
|
||||
close0(port);
|
||||
synchronized (staleIoSet) {
|
||||
for (Long ov: staleIoSet) {
|
||||
unsafe.freeMemory(ov);
|
||||
}
|
||||
staleIoSet.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isEmpty() {
|
||||
keyToChannelLock.writeLock().lock();
|
||||
try {
|
||||
return keyToChannel.isEmpty();
|
||||
} finally {
|
||||
keyToChannelLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
final Object attachForeignChannel(final Channel channel, FileDescriptor fdObj)
|
||||
throws IOException
|
||||
{
|
||||
int key = associate(new OverlappedChannel() {
|
||||
public <V,A> PendingFuture<V,A> getByOverlapped(long overlapped) {
|
||||
return null;
|
||||
}
|
||||
public void close() throws IOException {
|
||||
channel.close();
|
||||
}
|
||||
}, 0L);
|
||||
return Integer.valueOf(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
final void detachForeignChannel(Object key) {
|
||||
disassociate((Integer)key);
|
||||
}
|
||||
|
||||
@Override
|
||||
void closeAllChannels() {
|
||||
/**
|
||||
* On Windows the close operation will close the socket/file handle
|
||||
* and then wait until all outstanding I/O operations have aborted.
|
||||
* This is necessary as each channel's cache of OVERLAPPED structures
|
||||
* can only be freed once all I/O operations have completed. As I/O
|
||||
* completion requires a lookup of the keyToChannel then we must close
|
||||
* the channels when not holding the write lock.
|
||||
*/
|
||||
final int MAX_BATCH_SIZE = 32;
|
||||
OverlappedChannel channels[] = new OverlappedChannel[MAX_BATCH_SIZE];
|
||||
int count;
|
||||
do {
|
||||
// grab a batch of up to 32 channels
|
||||
keyToChannelLock.writeLock().lock();
|
||||
count = 0;
|
||||
try {
|
||||
for (Integer key: keyToChannel.keySet()) {
|
||||
channels[count++] = keyToChannel.get(key);
|
||||
if (count >= MAX_BATCH_SIZE)
|
||||
break;
|
||||
}
|
||||
} finally {
|
||||
keyToChannelLock.writeLock().unlock();
|
||||
}
|
||||
|
||||
// close them
|
||||
for (int i=0; i<count; i++) {
|
||||
try {
|
||||
channels[i].close();
|
||||
} catch (IOException ignore) { }
|
||||
}
|
||||
} while (count > 0);
|
||||
}
|
||||
|
||||
private void wakeup() {
|
||||
try {
|
||||
postQueuedCompletionStatus(port, 0);
|
||||
} catch (IOException e) {
|
||||
// should not happen
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void executeOnHandlerTask(Runnable task) {
|
||||
synchronized (this) {
|
||||
if (closed)
|
||||
throw new RejectedExecutionException();
|
||||
offerTask(task);
|
||||
wakeup();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
void shutdownHandlerTasks() {
|
||||
// shutdown all handler threads
|
||||
int nThreads = threadCount();
|
||||
while (nThreads-- > 0) {
|
||||
wakeup();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate the given handle with this group
|
||||
*/
|
||||
int associate(OverlappedChannel ch, long handle) throws IOException {
|
||||
keyToChannelLock.writeLock().lock();
|
||||
|
||||
// generate a completion key (if not shutdown)
|
||||
int key;
|
||||
try {
|
||||
if (isShutdown())
|
||||
throw new ShutdownChannelGroupException();
|
||||
|
||||
// generate unique key
|
||||
do {
|
||||
key = nextCompletionKey++;
|
||||
} while ((key == 0) || keyToChannel.containsKey(key));
|
||||
|
||||
// associate with I/O completion port
|
||||
if (handle != 0L) {
|
||||
createIoCompletionPort(handle, port, key, 0);
|
||||
}
|
||||
|
||||
// setup mapping
|
||||
keyToChannel.put(key, ch);
|
||||
} finally {
|
||||
keyToChannelLock.writeLock().unlock();
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disassociate channel from the group.
|
||||
*/
|
||||
void disassociate(int key) {
|
||||
boolean checkForShutdown = false;
|
||||
|
||||
keyToChannelLock.writeLock().lock();
|
||||
try {
|
||||
keyToChannel.remove(key);
|
||||
|
||||
// last key to be removed so check if group is shutdown
|
||||
if (keyToChannel.isEmpty())
|
||||
checkForShutdown = true;
|
||||
|
||||
} finally {
|
||||
keyToChannelLock.writeLock().unlock();
|
||||
}
|
||||
|
||||
// continue shutdown
|
||||
if (checkForShutdown && isShutdown()) {
|
||||
try {
|
||||
shutdownNow();
|
||||
} catch (IOException ignore) { }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when a channel associated with this port is closed before
|
||||
* notifications for all outstanding I/O operations have been received.
|
||||
*/
|
||||
void makeStale(Long overlapped) {
|
||||
synchronized (staleIoSet) {
|
||||
staleIoSet.add(overlapped);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given OVERLAPPED is stale and if so, releases it.
|
||||
*/
|
||||
private void checkIfStale(long ov) {
|
||||
synchronized (staleIoSet) {
|
||||
boolean removed = staleIoSet.remove(ov);
|
||||
if (removed) {
|
||||
unsafe.freeMemory(ov);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The handler for consuming the result of an asynchronous I/O operation.
|
||||
*/
|
||||
static interface ResultHandler {
|
||||
/**
|
||||
* Invoked if the I/O operation completes successfully.
|
||||
*/
|
||||
public void completed(int bytesTransferred, boolean canInvokeDirect);
|
||||
|
||||
/**
|
||||
* Invoked if the I/O operation fails.
|
||||
*/
|
||||
public void failed(int error, IOException ioe);
|
||||
}
|
||||
|
||||
// Creates IOException for the given I/O error.
|
||||
private static IOException translateErrorToIOException(int error) {
|
||||
String msg = getErrorMessage(error);
|
||||
if (msg == null)
|
||||
msg = "Unknown error: 0x0" + Integer.toHexString(error);
|
||||
return new IOException(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Long-running task servicing system-wide or per-file completion port
|
||||
*/
|
||||
private class EventHandlerTask implements Runnable {
|
||||
public void run() {
|
||||
Invoker.GroupAndInvokeCount myGroupAndInvokeCount =
|
||||
Invoker.getGroupAndInvokeCount();
|
||||
boolean canInvokeDirect = (myGroupAndInvokeCount != null);
|
||||
CompletionStatus ioResult = new CompletionStatus();
|
||||
boolean replaceMe = false;
|
||||
|
||||
try {
|
||||
for (;;) {
|
||||
// reset invoke count
|
||||
if (myGroupAndInvokeCount != null)
|
||||
myGroupAndInvokeCount.resetInvokeCount();
|
||||
|
||||
// wait for I/O completion event
|
||||
// A error here is fatal (thread will not be replaced)
|
||||
replaceMe = false;
|
||||
try {
|
||||
getQueuedCompletionStatus(port, ioResult);
|
||||
} catch (IOException x) {
|
||||
// should not happen
|
||||
x.printStackTrace();
|
||||
return;
|
||||
}
|
||||
|
||||
// handle wakeup to execute task or shutdown
|
||||
if (ioResult.completionKey() == 0 &&
|
||||
ioResult.overlapped() == 0L)
|
||||
{
|
||||
Runnable task = pollTask();
|
||||
if (task == null) {
|
||||
// shutdown request
|
||||
return;
|
||||
}
|
||||
|
||||
// run task
|
||||
// (if error/exception then replace thread)
|
||||
replaceMe = true;
|
||||
task.run();
|
||||
continue;
|
||||
}
|
||||
|
||||
// map key to channel
|
||||
OverlappedChannel ch = null;
|
||||
keyToChannelLock.readLock().lock();
|
||||
try {
|
||||
ch = keyToChannel.get(ioResult.completionKey());
|
||||
if (ch == null) {
|
||||
checkIfStale(ioResult.overlapped());
|
||||
continue;
|
||||
}
|
||||
} finally {
|
||||
keyToChannelLock.readLock().unlock();
|
||||
}
|
||||
|
||||
// lookup I/O request
|
||||
PendingFuture<?,?> result = ch.getByOverlapped(ioResult.overlapped());
|
||||
if (result == null) {
|
||||
// we get here if the OVERLAPPED structure is associated
|
||||
// with an I/O operation on a channel that was closed
|
||||
// but the I/O operation event wasn't read in a timely
|
||||
// manner. Alternatively, it may be related to a
|
||||
// tryLock operation as the OVERLAPPED structures for
|
||||
// these operations are not in the I/O cache.
|
||||
checkIfStale(ioResult.overlapped());
|
||||
continue;
|
||||
}
|
||||
|
||||
// synchronize on result in case I/O completed immediately
|
||||
// and was handled by initiator
|
||||
synchronized (result) {
|
||||
if (result.isDone()) {
|
||||
continue;
|
||||
}
|
||||
// not handled by initiator
|
||||
}
|
||||
|
||||
// invoke I/O result handler
|
||||
int error = ioResult.error();
|
||||
ResultHandler rh = (ResultHandler)result.getContext();
|
||||
replaceMe = true; // (if error/exception then replace thread)
|
||||
if (error == 0) {
|
||||
rh.completed(ioResult.bytesTransferred(), canInvokeDirect);
|
||||
} else {
|
||||
rh.failed(error, translateErrorToIOException(error));
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// last thread to exit when shutdown releases resources
|
||||
int remaining = threadExit(this, replaceMe);
|
||||
if (remaining == 0 && isShutdown()) {
|
||||
implClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Container for data returned by GetQueuedCompletionStatus
|
||||
*/
|
||||
private static class CompletionStatus {
|
||||
private int error;
|
||||
private int bytesTransferred;
|
||||
private int completionKey;
|
||||
private long overlapped;
|
||||
|
||||
private CompletionStatus() { }
|
||||
int error() { return error; }
|
||||
int bytesTransferred() { return bytesTransferred; }
|
||||
int completionKey() { return completionKey; }
|
||||
long overlapped() { return overlapped; }
|
||||
}
|
||||
|
||||
// -- native methods --
|
||||
|
||||
private static native void initIDs();
|
||||
|
||||
private static native long createIoCompletionPort(long handle,
|
||||
long existingPort, int completionKey, int concurrency) throws IOException;
|
||||
|
||||
private static native void close0(long handle);
|
||||
|
||||
private static native void getQueuedCompletionStatus(long completionPort,
|
||||
CompletionStatus status) throws IOException;
|
||||
|
||||
private static native void postQueuedCompletionStatus(long completionPort,
|
||||
int completionKey) throws IOException;
|
||||
|
||||
private static native String getErrorMessage(int error);
|
||||
|
||||
static {
|
||||
IOUtil.load();
|
||||
initIDs();
|
||||
}
|
||||
}
|
42
src/java.base/windows/classes/sun/nio/ch/NativeThread.java
Normal file
42
src/java.base/windows/classes/sun/nio/ch/NativeThread.java
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2002, 2012, 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 sun.nio.ch;
|
||||
|
||||
|
||||
// Signalling operations on native threads
|
||||
|
||||
|
||||
class NativeThread {
|
||||
|
||||
static long current() {
|
||||
// return 0 to ensure that async close of blocking sockets will close
|
||||
// the underlying socket.
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void signal(long nt) { }
|
||||
|
||||
}
|
163
src/java.base/windows/classes/sun/nio/ch/PendingIoCache.java
Normal file
163
src/java.base/windows/classes/sun/nio/ch/PendingIoCache.java
Normal file
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2011, 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 sun.nio.ch;
|
||||
|
||||
import java.nio.channels.*;
|
||||
import java.util.*;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
/**
|
||||
* Maintains a mapping of pending I/O requests (identified by the address of
|
||||
* an OVERLAPPED structure) to Futures.
|
||||
*/
|
||||
|
||||
class PendingIoCache {
|
||||
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||
private static final int addressSize = unsafe.addressSize();
|
||||
|
||||
private static int dependsArch(int value32, int value64) {
|
||||
return (addressSize == 4) ? value32 : value64;
|
||||
}
|
||||
|
||||
/*
|
||||
* typedef struct _OVERLAPPED {
|
||||
* DWORD Internal;
|
||||
* DWORD InternalHigh;
|
||||
* DWORD Offset;
|
||||
* DWORD OffsetHigh;
|
||||
* HANDLE hEvent;
|
||||
* } OVERLAPPED;
|
||||
*/
|
||||
private static final int SIZEOF_OVERLAPPED = dependsArch(20, 32);
|
||||
|
||||
// set to true when closed
|
||||
private boolean closed;
|
||||
|
||||
// set to true when thread is waiting for all I/O operations to complete
|
||||
private boolean closePending;
|
||||
|
||||
// maps OVERLAPPED to PendingFuture
|
||||
@SuppressWarnings("rawtypes")
|
||||
private final Map<Long,PendingFuture> pendingIoMap =
|
||||
new HashMap<Long,PendingFuture>();
|
||||
|
||||
// per-channel cache of OVERLAPPED structures
|
||||
private long[] overlappedCache = new long[4];
|
||||
private int overlappedCacheCount = 0;
|
||||
|
||||
PendingIoCache() {
|
||||
}
|
||||
|
||||
long add(PendingFuture<?,?> result) {
|
||||
synchronized (this) {
|
||||
if (closed)
|
||||
throw new AssertionError("Should not get here");
|
||||
long ov;
|
||||
if (overlappedCacheCount > 0) {
|
||||
ov = overlappedCache[--overlappedCacheCount];
|
||||
} else {
|
||||
ov = unsafe.allocateMemory(SIZEOF_OVERLAPPED);
|
||||
}
|
||||
pendingIoMap.put(ov, result);
|
||||
return ov;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
<V,A> PendingFuture<V,A> remove(long overlapped) {
|
||||
synchronized (this) {
|
||||
PendingFuture<V,A> res = pendingIoMap.remove(overlapped);
|
||||
if (res != null) {
|
||||
if (overlappedCacheCount < overlappedCache.length) {
|
||||
overlappedCache[overlappedCacheCount++] = overlapped;
|
||||
} else {
|
||||
// cache full or channel closing
|
||||
unsafe.freeMemory(overlapped);
|
||||
}
|
||||
// notify closing thread.
|
||||
if (closePending) {
|
||||
this.notifyAll();
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
void close() {
|
||||
synchronized (this) {
|
||||
if (closed)
|
||||
return;
|
||||
|
||||
// handle case where I/O operations that have not completed.
|
||||
if (!pendingIoMap.isEmpty())
|
||||
clearPendingIoMap();
|
||||
|
||||
// release memory for any cached OVERLAPPED structures
|
||||
while (overlappedCacheCount > 0) {
|
||||
unsafe.freeMemory( overlappedCache[--overlappedCacheCount] );
|
||||
}
|
||||
|
||||
// done
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void clearPendingIoMap() {
|
||||
assert Thread.holdsLock(this);
|
||||
|
||||
// wait up to 50ms for the I/O operations to complete
|
||||
closePending = true;
|
||||
try {
|
||||
this.wait(50);
|
||||
} catch (InterruptedException x) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
closePending = false;
|
||||
if (pendingIoMap.isEmpty())
|
||||
return;
|
||||
|
||||
// cause all pending I/O operations to fail
|
||||
// simulate the failure of all pending I/O operations.
|
||||
for (Long ov: pendingIoMap.keySet()) {
|
||||
PendingFuture<?,?> result = pendingIoMap.get(ov);
|
||||
assert !result.isDone();
|
||||
|
||||
// make I/O port aware of the stale OVERLAPPED structure
|
||||
Iocp iocp = (Iocp)((Groupable)result.channel()).group();
|
||||
iocp.makeStale(ov);
|
||||
|
||||
// execute a task that invokes the result handler's failed method
|
||||
final Iocp.ResultHandler rh = (Iocp.ResultHandler)result.getContext();
|
||||
Runnable task = new Runnable() {
|
||||
public void run() {
|
||||
rh.failed(-1, new AsynchronousCloseException());
|
||||
}
|
||||
};
|
||||
iocp.executeOnPooledThread(task);
|
||||
}
|
||||
pendingIoMap.clear();
|
||||
}
|
||||
}
|
185
src/java.base/windows/classes/sun/nio/ch/PipeImpl.java
Normal file
185
src/java.base/windows/classes/sun/nio/ch/PipeImpl.java
Normal file
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
* Copyright (c) 2002, 2016, 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 sun.nio.ch;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.*;
|
||||
import java.nio.channels.*;
|
||||
import java.nio.channels.spi.*;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Random;
|
||||
|
||||
|
||||
/**
|
||||
* A simple Pipe implementation based on a socket connection.
|
||||
*/
|
||||
|
||||
class PipeImpl
|
||||
extends Pipe
|
||||
{
|
||||
// Number of bytes in the secret handshake.
|
||||
private static final int NUM_SECRET_BYTES = 16;
|
||||
|
||||
// Random object for handshake values
|
||||
private static final Random RANDOM_NUMBER_GENERATOR = new SecureRandom();
|
||||
|
||||
// Source and sink channels
|
||||
private SourceChannel source;
|
||||
private SinkChannel sink;
|
||||
|
||||
private class Initializer
|
||||
implements PrivilegedExceptionAction<Void>
|
||||
{
|
||||
|
||||
private final SelectorProvider sp;
|
||||
|
||||
private IOException ioe = null;
|
||||
|
||||
private Initializer(SelectorProvider sp) {
|
||||
this.sp = sp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void run() throws IOException {
|
||||
LoopbackConnector connector = new LoopbackConnector();
|
||||
connector.run();
|
||||
if (ioe instanceof ClosedByInterruptException) {
|
||||
ioe = null;
|
||||
Thread connThread = new Thread(connector) {
|
||||
@Override
|
||||
public void interrupt() {}
|
||||
};
|
||||
connThread.start();
|
||||
for (;;) {
|
||||
try {
|
||||
connThread.join();
|
||||
break;
|
||||
} catch (InterruptedException ex) {}
|
||||
}
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
|
||||
if (ioe != null)
|
||||
throw new IOException("Unable to establish loopback connection", ioe);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private class LoopbackConnector implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
ServerSocketChannel ssc = null;
|
||||
SocketChannel sc1 = null;
|
||||
SocketChannel sc2 = null;
|
||||
|
||||
try {
|
||||
// Create secret with a backing array.
|
||||
ByteBuffer secret = ByteBuffer.allocate(NUM_SECRET_BYTES);
|
||||
ByteBuffer bb = ByteBuffer.allocate(NUM_SECRET_BYTES);
|
||||
|
||||
// Loopback address
|
||||
InetAddress lb = InetAddress.getByName("127.0.0.1");
|
||||
assert(lb.isLoopbackAddress());
|
||||
InetSocketAddress sa = null;
|
||||
for(;;) {
|
||||
// Bind ServerSocketChannel to a port on the loopback
|
||||
// address
|
||||
if (ssc == null || !ssc.isOpen()) {
|
||||
ssc = ServerSocketChannel.open();
|
||||
ssc.socket().bind(new InetSocketAddress(lb, 0));
|
||||
sa = new InetSocketAddress(lb, ssc.socket().getLocalPort());
|
||||
}
|
||||
|
||||
// Establish connection (assume connections are eagerly
|
||||
// accepted)
|
||||
sc1 = SocketChannel.open(sa);
|
||||
RANDOM_NUMBER_GENERATOR.nextBytes(secret.array());
|
||||
do {
|
||||
sc1.write(secret);
|
||||
} while (secret.hasRemaining());
|
||||
secret.rewind();
|
||||
|
||||
// Get a connection and verify it is legitimate
|
||||
sc2 = ssc.accept();
|
||||
do {
|
||||
sc2.read(bb);
|
||||
} while (bb.hasRemaining());
|
||||
bb.rewind();
|
||||
|
||||
if (bb.equals(secret))
|
||||
break;
|
||||
|
||||
sc2.close();
|
||||
sc1.close();
|
||||
}
|
||||
|
||||
// Create source and sink channels
|
||||
source = new SourceChannelImpl(sp, sc1);
|
||||
sink = new SinkChannelImpl(sp, sc2);
|
||||
} catch (IOException e) {
|
||||
try {
|
||||
if (sc1 != null)
|
||||
sc1.close();
|
||||
if (sc2 != null)
|
||||
sc2.close();
|
||||
} catch (IOException e2) {}
|
||||
ioe = e;
|
||||
} finally {
|
||||
try {
|
||||
if (ssc != null)
|
||||
ssc.close();
|
||||
} catch (IOException e2) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PipeImpl(final SelectorProvider sp) throws IOException {
|
||||
try {
|
||||
AccessController.doPrivileged(new Initializer(sp));
|
||||
} catch (PrivilegedActionException x) {
|
||||
throw (IOException)x.getCause();
|
||||
}
|
||||
}
|
||||
|
||||
public SourceChannel source() {
|
||||
return source;
|
||||
}
|
||||
|
||||
public SinkChannel sink() {
|
||||
return sink;
|
||||
}
|
||||
|
||||
}
|
115
src/java.base/windows/classes/sun/nio/ch/PollArrayWrapper.java
Normal file
115
src/java.base/windows/classes/sun/nio/ch/PollArrayWrapper.java
Normal file
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright (c) 2001, 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. 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 sun.nio.ch;
|
||||
|
||||
import java.lang.annotation.Native;
|
||||
|
||||
/**
|
||||
* Manipulates a native array of structs corresponding to (fd, events) pairs.
|
||||
*
|
||||
* typedef struct pollfd {
|
||||
* SOCKET fd; // 4 bytes
|
||||
* short events; // 2 bytes
|
||||
* } pollfd_t;
|
||||
*
|
||||
* @author Konstantin Kladko
|
||||
* @author Mike McCloskey
|
||||
*/
|
||||
|
||||
class PollArrayWrapper {
|
||||
|
||||
private AllocatedNativeObject pollArray; // The fd array
|
||||
|
||||
long pollArrayAddress; // pollArrayAddress
|
||||
|
||||
@Native private static final short FD_OFFSET = 0; // fd offset in pollfd
|
||||
@Native private static final short EVENT_OFFSET = 4; // events offset in pollfd
|
||||
|
||||
static short SIZE_POLLFD = 8; // sizeof pollfd struct
|
||||
|
||||
private int size; // Size of the pollArray
|
||||
|
||||
PollArrayWrapper(int newSize) {
|
||||
int allocationSize = newSize * SIZE_POLLFD;
|
||||
pollArray = new AllocatedNativeObject(allocationSize, true);
|
||||
pollArrayAddress = pollArray.address();
|
||||
this.size = newSize;
|
||||
}
|
||||
|
||||
// Prepare another pollfd struct for use.
|
||||
void addEntry(int index, SelectionKeyImpl ski) {
|
||||
putDescriptor(index, ski.channel.getFDVal());
|
||||
}
|
||||
|
||||
// Writes the pollfd entry from the source wrapper at the source index
|
||||
// over the entry in the target wrapper at the target index.
|
||||
void replaceEntry(PollArrayWrapper source, int sindex,
|
||||
PollArrayWrapper target, int tindex) {
|
||||
target.putDescriptor(tindex, source.getDescriptor(sindex));
|
||||
target.putEventOps(tindex, source.getEventOps(sindex));
|
||||
}
|
||||
|
||||
// Grows the pollfd array to new size
|
||||
void grow(int newSize) {
|
||||
PollArrayWrapper temp = new PollArrayWrapper(newSize);
|
||||
for (int i = 0; i < size; i++)
|
||||
replaceEntry(this, i, temp, i);
|
||||
pollArray.free();
|
||||
pollArray = temp.pollArray;
|
||||
this.size = temp.size;
|
||||
pollArrayAddress = pollArray.address();
|
||||
}
|
||||
|
||||
void free() {
|
||||
pollArray.free();
|
||||
}
|
||||
|
||||
// Access methods for fd structures
|
||||
void putDescriptor(int i, int fd) {
|
||||
pollArray.putInt(SIZE_POLLFD * i + FD_OFFSET, fd);
|
||||
}
|
||||
|
||||
void putEventOps(int i, int event) {
|
||||
pollArray.putShort(SIZE_POLLFD * i + EVENT_OFFSET, (short)event);
|
||||
}
|
||||
|
||||
int getEventOps(int i) {
|
||||
return pollArray.getShort(SIZE_POLLFD * i + EVENT_OFFSET);
|
||||
}
|
||||
|
||||
int getDescriptor(int i) {
|
||||
return pollArray.getInt(SIZE_POLLFD * i + FD_OFFSET);
|
||||
}
|
||||
|
||||
// Adds Windows wakeup socket at a given index.
|
||||
void addWakeupSocket(int fdVal, int index) {
|
||||
putDescriptor(index, fdVal);
|
||||
putEventOps(index, Net.POLLIN);
|
||||
}
|
||||
}
|
142
src/java.base/windows/classes/sun/nio/ch/SinkChannelImpl.java
Normal file
142
src/java.base/windows/classes/sun/nio/ch/SinkChannelImpl.java
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* Copyright (c) 2002, 2006, 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 sun.nio.ch;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.FileDescriptor;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.*;
|
||||
import java.nio.channels.spi.*;
|
||||
|
||||
|
||||
/**
|
||||
* Pipe.SinkChannel implementation based on socket connection.
|
||||
*/
|
||||
|
||||
class SinkChannelImpl
|
||||
extends Pipe.SinkChannel
|
||||
implements SelChImpl
|
||||
{
|
||||
// The SocketChannel assoicated with this pipe
|
||||
SocketChannel sc;
|
||||
|
||||
public FileDescriptor getFD() {
|
||||
return ((SocketChannelImpl)sc).getFD();
|
||||
}
|
||||
|
||||
public int getFDVal() {
|
||||
return ((SocketChannelImpl)sc).getFDVal();
|
||||
}
|
||||
|
||||
SinkChannelImpl(SelectorProvider sp, SocketChannel sc) {
|
||||
super(sp);
|
||||
this.sc = sc;
|
||||
}
|
||||
|
||||
protected void implCloseSelectableChannel() throws IOException {
|
||||
if (!isRegistered())
|
||||
kill();
|
||||
}
|
||||
|
||||
public void kill() throws IOException {
|
||||
sc.close();
|
||||
}
|
||||
|
||||
protected void implConfigureBlocking(boolean block) throws IOException {
|
||||
sc.configureBlocking(block);
|
||||
}
|
||||
|
||||
public boolean translateReadyOps(int ops, int initialOps,
|
||||
SelectionKeyImpl sk) {
|
||||
int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes
|
||||
int oldOps = sk.nioReadyOps();
|
||||
int newOps = initialOps;
|
||||
|
||||
if ((ops & Net.POLLNVAL) != 0)
|
||||
throw new Error("POLLNVAL detected");
|
||||
|
||||
if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
|
||||
newOps = intOps;
|
||||
sk.nioReadyOps(newOps);
|
||||
return (newOps & ~oldOps) != 0;
|
||||
}
|
||||
|
||||
if (((ops & Net.POLLOUT) != 0) &&
|
||||
((intOps & SelectionKey.OP_WRITE) != 0))
|
||||
newOps |= SelectionKey.OP_WRITE;
|
||||
|
||||
sk.nioReadyOps(newOps);
|
||||
return (newOps & ~oldOps) != 0;
|
||||
}
|
||||
|
||||
public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
|
||||
return translateReadyOps(ops, sk.nioReadyOps(), sk);
|
||||
}
|
||||
|
||||
public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
|
||||
return translateReadyOps(ops, 0, sk);
|
||||
}
|
||||
|
||||
public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
|
||||
if ((ops & SelectionKey.OP_WRITE) != 0)
|
||||
ops = Net.POLLOUT;
|
||||
sk.selector.putEventOps(sk, ops);
|
||||
}
|
||||
|
||||
public int write(ByteBuffer src) throws IOException {
|
||||
try {
|
||||
return sc.write(src);
|
||||
} catch (AsynchronousCloseException x) {
|
||||
close();
|
||||
throw x;
|
||||
}
|
||||
}
|
||||
|
||||
public long write(ByteBuffer[] srcs) throws IOException {
|
||||
try {
|
||||
return sc.write(srcs);
|
||||
} catch (AsynchronousCloseException x) {
|
||||
close();
|
||||
throw x;
|
||||
}
|
||||
}
|
||||
|
||||
public long write(ByteBuffer[] srcs, int offset, int length)
|
||||
throws IOException
|
||||
{
|
||||
if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
|
||||
throw new IndexOutOfBoundsException();
|
||||
try {
|
||||
return write(Util.subsequence(srcs, offset, length));
|
||||
} catch (AsynchronousCloseException x) {
|
||||
close();
|
||||
throw x;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 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. 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 sun.nio.ch;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* Allows different platforms to call different native methods
|
||||
* for read and write operations.
|
||||
*/
|
||||
|
||||
class SocketDispatcher extends NativeDispatcher
|
||||
{
|
||||
|
||||
static {
|
||||
IOUtil.load();
|
||||
}
|
||||
|
||||
int read(FileDescriptor fd, long address, int len) throws IOException {
|
||||
return read0(fd, address, len);
|
||||
}
|
||||
|
||||
long readv(FileDescriptor fd, long address, int len) throws IOException {
|
||||
return readv0(fd, address, len);
|
||||
}
|
||||
|
||||
int write(FileDescriptor fd, long address, int len) throws IOException {
|
||||
return write0(fd, address, len);
|
||||
}
|
||||
|
||||
long writev(FileDescriptor fd, long address, int len) throws IOException {
|
||||
return writev0(fd, address, len);
|
||||
}
|
||||
|
||||
void preClose(FileDescriptor fd) throws IOException {
|
||||
preClose0(fd);
|
||||
}
|
||||
|
||||
void close(FileDescriptor fd) throws IOException {
|
||||
close0(fd);
|
||||
}
|
||||
|
||||
//-- Native methods
|
||||
static native int read0(FileDescriptor fd, long address, int len)
|
||||
throws IOException;
|
||||
|
||||
static native long readv0(FileDescriptor fd, long address, int len)
|
||||
throws IOException;
|
||||
|
||||
static native int write0(FileDescriptor fd, long address, int len)
|
||||
throws IOException;
|
||||
|
||||
static native long writev0(FileDescriptor fd, long address, int len)
|
||||
throws IOException;
|
||||
|
||||
static native void preClose0(FileDescriptor fd) throws IOException;
|
||||
|
||||
static native void close0(FileDescriptor fd) throws IOException;
|
||||
}
|
142
src/java.base/windows/classes/sun/nio/ch/SourceChannelImpl.java
Normal file
142
src/java.base/windows/classes/sun/nio/ch/SourceChannelImpl.java
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* Copyright (c) 2002, 2006, 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 sun.nio.ch;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.FileDescriptor;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.*;
|
||||
import java.nio.channels.spi.*;
|
||||
|
||||
/**
|
||||
* Pipe.SourceChannel implementation based on socket connection.
|
||||
*/
|
||||
|
||||
class SourceChannelImpl
|
||||
extends Pipe.SourceChannel
|
||||
implements SelChImpl
|
||||
{
|
||||
// The SocketChannel assoicated with this pipe
|
||||
SocketChannel sc;
|
||||
|
||||
public FileDescriptor getFD() {
|
||||
return ((SocketChannelImpl) sc).getFD();
|
||||
}
|
||||
|
||||
public int getFDVal() {
|
||||
return ((SocketChannelImpl) sc).getFDVal();
|
||||
}
|
||||
|
||||
SourceChannelImpl(SelectorProvider sp, SocketChannel sc) {
|
||||
super(sp);
|
||||
this.sc = sc;
|
||||
}
|
||||
|
||||
protected void implCloseSelectableChannel() throws IOException {
|
||||
if (!isRegistered())
|
||||
kill();
|
||||
}
|
||||
|
||||
public void kill() throws IOException {
|
||||
sc.close();
|
||||
}
|
||||
|
||||
protected void implConfigureBlocking(boolean block) throws IOException {
|
||||
sc.configureBlocking(block);
|
||||
}
|
||||
|
||||
public boolean translateReadyOps(int ops, int initialOps,
|
||||
SelectionKeyImpl sk) {
|
||||
int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes
|
||||
int oldOps = sk.nioReadyOps();
|
||||
int newOps = initialOps;
|
||||
|
||||
if ((ops & Net.POLLNVAL) != 0)
|
||||
throw new Error("POLLNVAL detected");
|
||||
|
||||
if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
|
||||
newOps = intOps;
|
||||
sk.nioReadyOps(newOps);
|
||||
return (newOps & ~oldOps) != 0;
|
||||
}
|
||||
|
||||
if (((ops & Net.POLLIN) != 0) &&
|
||||
((intOps & SelectionKey.OP_READ) != 0))
|
||||
newOps |= SelectionKey.OP_READ;
|
||||
|
||||
sk.nioReadyOps(newOps);
|
||||
return (newOps & ~oldOps) != 0;
|
||||
}
|
||||
|
||||
public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
|
||||
return translateReadyOps(ops, sk.nioReadyOps(), sk);
|
||||
}
|
||||
|
||||
public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
|
||||
return translateReadyOps(ops, 0, sk);
|
||||
}
|
||||
|
||||
public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
|
||||
if ((ops & SelectionKey.OP_READ) != 0)
|
||||
ops = Net.POLLIN;
|
||||
sk.selector.putEventOps(sk, ops);
|
||||
}
|
||||
|
||||
public int read(ByteBuffer dst) throws IOException {
|
||||
try {
|
||||
return sc.read(dst);
|
||||
} catch (AsynchronousCloseException x) {
|
||||
close();
|
||||
throw x;
|
||||
}
|
||||
}
|
||||
|
||||
public long read(ByteBuffer[] dsts, int offset, int length)
|
||||
throws IOException
|
||||
{
|
||||
if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
|
||||
throw new IndexOutOfBoundsException();
|
||||
try {
|
||||
return read(Util.subsequence(dsts, offset, length));
|
||||
} catch (AsynchronousCloseException x) {
|
||||
close();
|
||||
throw x;
|
||||
}
|
||||
}
|
||||
|
||||
public long read(ByteBuffer[] dsts) throws IOException {
|
||||
try {
|
||||
return sc.read(dsts);
|
||||
} catch (AsynchronousCloseException x) {
|
||||
close();
|
||||
throw x;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2010, 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 sun.nio.ch;
|
||||
|
||||
import java.nio.channels.*;
|
||||
import java.nio.channels.spi.AsynchronousChannelProvider;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.io.IOException;
|
||||
|
||||
public class WindowsAsynchronousChannelProvider
|
||||
extends AsynchronousChannelProvider
|
||||
{
|
||||
private static volatile Iocp defaultIocp;
|
||||
|
||||
public WindowsAsynchronousChannelProvider() {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
private Iocp defaultIocp() throws IOException {
|
||||
if (defaultIocp == null) {
|
||||
synchronized (WindowsAsynchronousChannelProvider.class) {
|
||||
if (defaultIocp == null) {
|
||||
// default thread pool may be shared with AsynchronousFileChannels
|
||||
defaultIocp = new Iocp(this, ThreadPool.getDefault()).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
return defaultIocp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousChannelGroup openAsynchronousChannelGroup(int nThreads, ThreadFactory factory)
|
||||
throws IOException
|
||||
{
|
||||
return new Iocp(this, ThreadPool.create(nThreads, factory)).start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousChannelGroup openAsynchronousChannelGroup(ExecutorService executor, int initialSize)
|
||||
throws IOException
|
||||
{
|
||||
return new Iocp(this, ThreadPool.wrap(executor, initialSize)).start();
|
||||
}
|
||||
|
||||
private Iocp toIocp(AsynchronousChannelGroup group) throws IOException {
|
||||
if (group == null) {
|
||||
return defaultIocp();
|
||||
} else {
|
||||
if (!(group instanceof Iocp))
|
||||
throw new IllegalChannelGroupException();
|
||||
return (Iocp)group;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousServerSocketChannel openAsynchronousServerSocketChannel(AsynchronousChannelGroup group)
|
||||
throws IOException
|
||||
{
|
||||
return new WindowsAsynchronousServerSocketChannelImpl(toIocp(group));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousSocketChannel openAsynchronousSocketChannel(AsynchronousChannelGroup group)
|
||||
throws IOException
|
||||
{
|
||||
return new WindowsAsynchronousSocketChannelImpl(toIocp(group));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,736 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 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. 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 sun.nio.ch;
|
||||
|
||||
import java.nio.channels.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.io.IOException;
|
||||
import java.io.FileDescriptor;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import jdk.internal.misc.JavaIOFileDescriptorAccess;
|
||||
|
||||
/**
|
||||
* Windows implementation of AsynchronousFileChannel using overlapped I/O.
|
||||
*/
|
||||
|
||||
public class WindowsAsynchronousFileChannelImpl
|
||||
extends AsynchronousFileChannelImpl
|
||||
implements Iocp.OverlappedChannel, Groupable
|
||||
{
|
||||
private static final JavaIOFileDescriptorAccess fdAccess =
|
||||
SharedSecrets.getJavaIOFileDescriptorAccess();
|
||||
|
||||
// error when EOF is detected asynchronously.
|
||||
private static final int ERROR_HANDLE_EOF = 38;
|
||||
|
||||
// Lazy initialization of default I/O completion port
|
||||
private static class DefaultIocpHolder {
|
||||
static final Iocp defaultIocp = defaultIocp();
|
||||
private static Iocp defaultIocp() {
|
||||
try {
|
||||
return new Iocp(null, ThreadPool.createDefault()).start();
|
||||
} catch (IOException ioe) {
|
||||
throw new InternalError(ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Used for force/truncate/size methods
|
||||
private static final FileDispatcher nd = new FileDispatcherImpl();
|
||||
|
||||
// The handle is extracted for use in native methods invoked from this class.
|
||||
private final long handle;
|
||||
|
||||
// The key that identifies the channel's association with the I/O port
|
||||
private final int completionKey;
|
||||
|
||||
// I/O completion port (group)
|
||||
private final Iocp iocp;
|
||||
|
||||
private final boolean isDefaultIocp;
|
||||
|
||||
// Caches OVERLAPPED structure for each outstanding I/O operation
|
||||
private final PendingIoCache ioCache;
|
||||
|
||||
|
||||
private WindowsAsynchronousFileChannelImpl(FileDescriptor fdObj,
|
||||
boolean reading,
|
||||
boolean writing,
|
||||
Iocp iocp,
|
||||
boolean isDefaultIocp)
|
||||
throws IOException
|
||||
{
|
||||
super(fdObj, reading, writing, iocp.executor());
|
||||
this.handle = fdAccess.getHandle(fdObj);
|
||||
this.iocp = iocp;
|
||||
this.isDefaultIocp = isDefaultIocp;
|
||||
this.ioCache = new PendingIoCache();
|
||||
this.completionKey = iocp.associate(this, handle);
|
||||
}
|
||||
|
||||
public static AsynchronousFileChannel open(FileDescriptor fdo,
|
||||
boolean reading,
|
||||
boolean writing,
|
||||
ThreadPool pool)
|
||||
throws IOException
|
||||
{
|
||||
Iocp iocp;
|
||||
boolean isDefaultIocp;
|
||||
if (pool == null) {
|
||||
iocp = DefaultIocpHolder.defaultIocp;
|
||||
isDefaultIocp = true;
|
||||
} else {
|
||||
iocp = new Iocp(null, pool).start();
|
||||
isDefaultIocp = false;
|
||||
}
|
||||
try {
|
||||
return new
|
||||
WindowsAsynchronousFileChannelImpl(fdo, reading, writing, iocp, isDefaultIocp);
|
||||
} catch (IOException x) {
|
||||
// error binding to port so need to close it (if created for this channel)
|
||||
if (!isDefaultIocp)
|
||||
iocp.implClose();
|
||||
throw x;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V,A> PendingFuture<V,A> getByOverlapped(long overlapped) {
|
||||
return ioCache.remove(overlapped);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
closeLock.writeLock().lock();
|
||||
try {
|
||||
if (closed)
|
||||
return; // already closed
|
||||
closed = true;
|
||||
} finally {
|
||||
closeLock.writeLock().unlock();
|
||||
}
|
||||
|
||||
// invalidate all locks held for this channel
|
||||
invalidateAllLocks();
|
||||
|
||||
// close the file
|
||||
close0(handle);
|
||||
|
||||
// waits until all I/O operations have completed
|
||||
ioCache.close();
|
||||
|
||||
// disassociate from port
|
||||
iocp.disassociate(completionKey);
|
||||
|
||||
// for the non-default group close the port
|
||||
if (!isDefaultIocp)
|
||||
iocp.detachFromThreadPool();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousChannelGroupImpl group() {
|
||||
return iocp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates Throwable to IOException
|
||||
*/
|
||||
private static IOException toIOException(Throwable x) {
|
||||
if (x instanceof IOException) {
|
||||
if (x instanceof ClosedChannelException)
|
||||
x = new AsynchronousCloseException();
|
||||
return (IOException)x;
|
||||
}
|
||||
return new IOException(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long size() throws IOException {
|
||||
try {
|
||||
begin();
|
||||
return nd.size(fdObj);
|
||||
} finally {
|
||||
end();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousFileChannel truncate(long size) throws IOException {
|
||||
if (size < 0)
|
||||
throw new IllegalArgumentException("Negative size");
|
||||
if (!writing)
|
||||
throw new NonWritableChannelException();
|
||||
try {
|
||||
begin();
|
||||
if (size > nd.size(fdObj))
|
||||
return this;
|
||||
nd.truncate(fdObj, size);
|
||||
} finally {
|
||||
end();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void force(boolean metaData) throws IOException {
|
||||
try {
|
||||
begin();
|
||||
nd.force(fdObj, metaData);
|
||||
} finally {
|
||||
end();
|
||||
}
|
||||
}
|
||||
|
||||
// -- file locking --
|
||||
|
||||
/**
|
||||
* Task that initiates locking operation and handles completion result.
|
||||
*/
|
||||
private class LockTask<A> implements Runnable, Iocp.ResultHandler {
|
||||
private final long position;
|
||||
private final FileLockImpl fli;
|
||||
private final PendingFuture<FileLock,A> result;
|
||||
|
||||
LockTask(long position,
|
||||
FileLockImpl fli,
|
||||
PendingFuture<FileLock,A> result)
|
||||
{
|
||||
this.position = position;
|
||||
this.fli = fli;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
long overlapped = 0L;
|
||||
boolean pending = false;
|
||||
try {
|
||||
begin();
|
||||
|
||||
// allocate OVERLAPPED structure
|
||||
overlapped = ioCache.add(result);
|
||||
|
||||
// synchronize on result to avoid race with handler thread
|
||||
// when lock is acquired immediately.
|
||||
synchronized (result) {
|
||||
int n = lockFile(handle, position, fli.size(), fli.isShared(),
|
||||
overlapped);
|
||||
if (n == IOStatus.UNAVAILABLE) {
|
||||
// I/O is pending
|
||||
pending = true;
|
||||
return;
|
||||
}
|
||||
// acquired lock immediately
|
||||
result.setResult(fli);
|
||||
}
|
||||
|
||||
} catch (Throwable x) {
|
||||
// lock failed or channel closed
|
||||
removeFromFileLockTable(fli);
|
||||
result.setFailure(toIOException(x));
|
||||
} finally {
|
||||
if (!pending && overlapped != 0L)
|
||||
ioCache.remove(overlapped);
|
||||
end();
|
||||
}
|
||||
|
||||
// invoke completion handler
|
||||
Invoker.invoke(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completed(int bytesTransferred, boolean canInvokeDirect) {
|
||||
// release waiters and invoke completion handler
|
||||
result.setResult(fli);
|
||||
if (canInvokeDirect) {
|
||||
Invoker.invokeUnchecked(result);
|
||||
} else {
|
||||
Invoker.invoke(result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(int error, IOException x) {
|
||||
// lock not acquired so remove from lock table
|
||||
removeFromFileLockTable(fli);
|
||||
|
||||
// release waiters
|
||||
if (isOpen()) {
|
||||
result.setFailure(x);
|
||||
} else {
|
||||
result.setFailure(new AsynchronousCloseException());
|
||||
}
|
||||
Invoker.invoke(result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
<A> Future<FileLock> implLock(final long position,
|
||||
final long size,
|
||||
final boolean shared,
|
||||
A attachment,
|
||||
final CompletionHandler<FileLock,? super A> handler)
|
||||
{
|
||||
if (shared && !reading)
|
||||
throw new NonReadableChannelException();
|
||||
if (!shared && !writing)
|
||||
throw new NonWritableChannelException();
|
||||
|
||||
// add to lock table
|
||||
FileLockImpl fli = addToFileLockTable(position, size, shared);
|
||||
if (fli == null) {
|
||||
Throwable exc = new ClosedChannelException();
|
||||
if (handler == null)
|
||||
return CompletedFuture.withFailure(exc);
|
||||
Invoker.invoke(this, handler, attachment, null, exc);
|
||||
return null;
|
||||
}
|
||||
|
||||
// create Future and task that will be invoked to acquire lock
|
||||
PendingFuture<FileLock,A> result =
|
||||
new PendingFuture<FileLock,A>(this, handler, attachment);
|
||||
LockTask<A> lockTask = new LockTask<A>(position, fli, result);
|
||||
result.setContext(lockTask);
|
||||
|
||||
// initiate I/O
|
||||
lockTask.run();
|
||||
return result;
|
||||
}
|
||||
|
||||
static final int NO_LOCK = -1; // Failed to lock
|
||||
static final int LOCKED = 0; // Obtained requested lock
|
||||
|
||||
@Override
|
||||
public FileLock tryLock(long position, long size, boolean shared)
|
||||
throws IOException
|
||||
{
|
||||
if (shared && !reading)
|
||||
throw new NonReadableChannelException();
|
||||
if (!shared && !writing)
|
||||
throw new NonWritableChannelException();
|
||||
|
||||
// add to lock table
|
||||
final FileLockImpl fli = addToFileLockTable(position, size, shared);
|
||||
if (fli == null)
|
||||
throw new ClosedChannelException();
|
||||
|
||||
boolean gotLock = false;
|
||||
try {
|
||||
begin();
|
||||
// try to acquire the lock
|
||||
int res = nd.lock(fdObj, false, position, size, shared);
|
||||
if (res == NO_LOCK)
|
||||
return null;
|
||||
gotLock = true;
|
||||
return fli;
|
||||
} finally {
|
||||
if (!gotLock)
|
||||
removeFromFileLockTable(fli);
|
||||
end();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void implRelease(FileLockImpl fli) throws IOException {
|
||||
nd.release(fdObj, fli.position(), fli.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Task that initiates read operation and handles completion result.
|
||||
*/
|
||||
private class ReadTask<A> implements Runnable, Iocp.ResultHandler {
|
||||
private final ByteBuffer dst;
|
||||
private final int pos, rem; // buffer position/remaining
|
||||
private final long position; // file position
|
||||
private final PendingFuture<Integer,A> result;
|
||||
|
||||
// set to dst if direct; otherwise set to substituted direct buffer
|
||||
private volatile ByteBuffer buf;
|
||||
|
||||
ReadTask(ByteBuffer dst,
|
||||
int pos,
|
||||
int rem,
|
||||
long position,
|
||||
PendingFuture<Integer,A> result)
|
||||
{
|
||||
this.dst = dst;
|
||||
this.pos = pos;
|
||||
this.rem = rem;
|
||||
this.position = position;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
void releaseBufferIfSubstituted() {
|
||||
if (buf != dst)
|
||||
Util.releaseTemporaryDirectBuffer(buf);
|
||||
}
|
||||
|
||||
void updatePosition(int bytesTransferred) {
|
||||
// if the I/O succeeded then adjust buffer position
|
||||
if (bytesTransferred > 0) {
|
||||
if (buf == dst) {
|
||||
try {
|
||||
dst.position(pos + bytesTransferred);
|
||||
} catch (IllegalArgumentException x) {
|
||||
// someone has changed the position; ignore
|
||||
}
|
||||
} else {
|
||||
// had to substitute direct buffer
|
||||
buf.position(bytesTransferred).flip();
|
||||
try {
|
||||
dst.put(buf);
|
||||
} catch (BufferOverflowException x) {
|
||||
// someone has changed the position; ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
int n = -1;
|
||||
long overlapped = 0L;
|
||||
long address;
|
||||
|
||||
// Substitute a native buffer if not direct
|
||||
if (dst instanceof DirectBuffer) {
|
||||
buf = dst;
|
||||
address = ((DirectBuffer)dst).address() + pos;
|
||||
} else {
|
||||
buf = Util.getTemporaryDirectBuffer(rem);
|
||||
address = ((DirectBuffer)buf).address();
|
||||
}
|
||||
|
||||
boolean pending = false;
|
||||
try {
|
||||
begin();
|
||||
|
||||
// allocate OVERLAPPED
|
||||
overlapped = ioCache.add(result);
|
||||
|
||||
// initiate read
|
||||
n = readFile(handle, address, rem, position, overlapped);
|
||||
if (n == IOStatus.UNAVAILABLE) {
|
||||
// I/O is pending
|
||||
pending = true;
|
||||
return;
|
||||
} else if (n == IOStatus.EOF) {
|
||||
result.setResult(n);
|
||||
} else {
|
||||
throw new InternalError("Unexpected result: " + n);
|
||||
}
|
||||
|
||||
} catch (Throwable x) {
|
||||
// failed to initiate read
|
||||
result.setFailure(toIOException(x));
|
||||
} finally {
|
||||
if (!pending) {
|
||||
// release resources
|
||||
if (overlapped != 0L)
|
||||
ioCache.remove(overlapped);
|
||||
releaseBufferIfSubstituted();
|
||||
}
|
||||
end();
|
||||
}
|
||||
|
||||
// invoke completion handler
|
||||
Invoker.invoke(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executed when the I/O has completed
|
||||
*/
|
||||
@Override
|
||||
public void completed(int bytesTransferred, boolean canInvokeDirect) {
|
||||
updatePosition(bytesTransferred);
|
||||
|
||||
// return direct buffer to cache if substituted
|
||||
releaseBufferIfSubstituted();
|
||||
|
||||
// release waiters and invoke completion handler
|
||||
result.setResult(bytesTransferred);
|
||||
if (canInvokeDirect) {
|
||||
Invoker.invokeUnchecked(result);
|
||||
} else {
|
||||
Invoker.invoke(result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(int error, IOException x) {
|
||||
// if EOF detected asynchronously then it is reported as error
|
||||
if (error == ERROR_HANDLE_EOF) {
|
||||
completed(-1, false);
|
||||
} else {
|
||||
// return direct buffer to cache if substituted
|
||||
releaseBufferIfSubstituted();
|
||||
|
||||
// release waiters
|
||||
if (isOpen()) {
|
||||
result.setFailure(x);
|
||||
} else {
|
||||
result.setFailure(new AsynchronousCloseException());
|
||||
}
|
||||
Invoker.invoke(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
<A> Future<Integer> implRead(ByteBuffer dst,
|
||||
long position,
|
||||
A attachment,
|
||||
CompletionHandler<Integer,? super A> handler)
|
||||
{
|
||||
if (!reading)
|
||||
throw new NonReadableChannelException();
|
||||
if (position < 0)
|
||||
throw new IllegalArgumentException("Negative position");
|
||||
if (dst.isReadOnly())
|
||||
throw new IllegalArgumentException("Read-only buffer");
|
||||
|
||||
// check if channel is closed
|
||||
if (!isOpen()) {
|
||||
Throwable exc = new ClosedChannelException();
|
||||
if (handler == null)
|
||||
return CompletedFuture.withFailure(exc);
|
||||
Invoker.invoke(this, handler, attachment, null, exc);
|
||||
return null;
|
||||
}
|
||||
|
||||
int pos = dst.position();
|
||||
int lim = dst.limit();
|
||||
assert (pos <= lim);
|
||||
int rem = (pos <= lim ? lim - pos : 0);
|
||||
|
||||
// no space remaining
|
||||
if (rem == 0) {
|
||||
if (handler == null)
|
||||
return CompletedFuture.withResult(0);
|
||||
Invoker.invoke(this, handler, attachment, 0, null);
|
||||
return null;
|
||||
}
|
||||
|
||||
// create Future and task that initiates read
|
||||
PendingFuture<Integer,A> result =
|
||||
new PendingFuture<Integer,A>(this, handler, attachment);
|
||||
ReadTask<A> readTask = new ReadTask<A>(dst, pos, rem, position, result);
|
||||
result.setContext(readTask);
|
||||
|
||||
// initiate I/O
|
||||
readTask.run();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Task that initiates write operation and handles completion result.
|
||||
*/
|
||||
private class WriteTask<A> implements Runnable, Iocp.ResultHandler {
|
||||
private final ByteBuffer src;
|
||||
private final int pos, rem; // buffer position/remaining
|
||||
private final long position; // file position
|
||||
private final PendingFuture<Integer,A> result;
|
||||
|
||||
// set to src if direct; otherwise set to substituted direct buffer
|
||||
private volatile ByteBuffer buf;
|
||||
|
||||
WriteTask(ByteBuffer src,
|
||||
int pos,
|
||||
int rem,
|
||||
long position,
|
||||
PendingFuture<Integer,A> result)
|
||||
{
|
||||
this.src = src;
|
||||
this.pos = pos;
|
||||
this.rem = rem;
|
||||
this.position = position;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
void releaseBufferIfSubstituted() {
|
||||
if (buf != src)
|
||||
Util.releaseTemporaryDirectBuffer(buf);
|
||||
}
|
||||
|
||||
void updatePosition(int bytesTransferred) {
|
||||
// if the I/O succeeded then adjust buffer position
|
||||
if (bytesTransferred > 0) {
|
||||
try {
|
||||
src.position(pos + bytesTransferred);
|
||||
} catch (IllegalArgumentException x) {
|
||||
// someone has changed the position
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
int n = -1;
|
||||
long overlapped = 0L;
|
||||
long address;
|
||||
|
||||
// Substitute a native buffer if not direct
|
||||
if (src instanceof DirectBuffer) {
|
||||
buf = src;
|
||||
address = ((DirectBuffer)src).address() + pos;
|
||||
} else {
|
||||
buf = Util.getTemporaryDirectBuffer(rem);
|
||||
buf.put(src);
|
||||
buf.flip();
|
||||
// temporarily restore position as we don't know how many bytes
|
||||
// will be written
|
||||
src.position(pos);
|
||||
address = ((DirectBuffer)buf).address();
|
||||
}
|
||||
|
||||
try {
|
||||
begin();
|
||||
|
||||
// allocate an OVERLAPPED structure
|
||||
overlapped = ioCache.add(result);
|
||||
|
||||
// initiate the write
|
||||
n = writeFile(handle, address, rem, position, overlapped);
|
||||
if (n == IOStatus.UNAVAILABLE) {
|
||||
// I/O is pending
|
||||
return;
|
||||
} else {
|
||||
throw new InternalError("Unexpected result: " + n);
|
||||
}
|
||||
|
||||
} catch (Throwable x) {
|
||||
// failed to initiate read:
|
||||
result.setFailure(toIOException(x));
|
||||
|
||||
// release resources
|
||||
if (overlapped != 0L)
|
||||
ioCache.remove(overlapped);
|
||||
releaseBufferIfSubstituted();
|
||||
|
||||
} finally {
|
||||
end();
|
||||
}
|
||||
|
||||
// invoke completion handler
|
||||
Invoker.invoke(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executed when the I/O has completed
|
||||
*/
|
||||
@Override
|
||||
public void completed(int bytesTransferred, boolean canInvokeDirect) {
|
||||
updatePosition(bytesTransferred);
|
||||
|
||||
// return direct buffer to cache if substituted
|
||||
releaseBufferIfSubstituted();
|
||||
|
||||
// release waiters and invoke completion handler
|
||||
result.setResult(bytesTransferred);
|
||||
if (canInvokeDirect) {
|
||||
Invoker.invokeUnchecked(result);
|
||||
} else {
|
||||
Invoker.invoke(result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(int error, IOException x) {
|
||||
// return direct buffer to cache if substituted
|
||||
releaseBufferIfSubstituted();
|
||||
|
||||
// release waiters and invoker completion handler
|
||||
if (isOpen()) {
|
||||
result.setFailure(x);
|
||||
} else {
|
||||
result.setFailure(new AsynchronousCloseException());
|
||||
}
|
||||
Invoker.invoke(result);
|
||||
}
|
||||
}
|
||||
|
||||
<A> Future<Integer> implWrite(ByteBuffer src,
|
||||
long position,
|
||||
A attachment,
|
||||
CompletionHandler<Integer,? super A> handler)
|
||||
{
|
||||
if (!writing)
|
||||
throw new NonWritableChannelException();
|
||||
if (position < 0)
|
||||
throw new IllegalArgumentException("Negative position");
|
||||
|
||||
// check if channel is closed
|
||||
if (!isOpen()) {
|
||||
Throwable exc = new ClosedChannelException();
|
||||
if (handler == null)
|
||||
return CompletedFuture.withFailure(exc);
|
||||
Invoker.invoke(this, handler, attachment, null, exc);
|
||||
return null;
|
||||
}
|
||||
|
||||
int pos = src.position();
|
||||
int lim = src.limit();
|
||||
assert (pos <= lim);
|
||||
int rem = (pos <= lim ? lim - pos : 0);
|
||||
|
||||
// nothing to write
|
||||
if (rem == 0) {
|
||||
if (handler == null)
|
||||
return CompletedFuture.withResult(0);
|
||||
Invoker.invoke(this, handler, attachment, 0, null);
|
||||
return null;
|
||||
}
|
||||
|
||||
// create Future and task to initiate write
|
||||
PendingFuture<Integer,A> result =
|
||||
new PendingFuture<Integer,A>(this, handler, attachment);
|
||||
WriteTask<A> writeTask = new WriteTask<A>(src, pos, rem, position, result);
|
||||
result.setContext(writeTask);
|
||||
|
||||
// initiate I/O
|
||||
writeTask.run();
|
||||
return result;
|
||||
}
|
||||
|
||||
// -- Native methods --
|
||||
|
||||
private static native int readFile(long handle, long address, int len,
|
||||
long offset, long overlapped) throws IOException;
|
||||
|
||||
private static native int writeFile(long handle, long address, int len,
|
||||
long offset, long overlapped) throws IOException;
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,365 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 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. 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 sun.nio.ch;
|
||||
|
||||
import java.nio.channels.*;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.io.IOException;
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
/**
|
||||
* Windows implementation of AsynchronousServerSocketChannel using overlapped I/O.
|
||||
*/
|
||||
|
||||
class WindowsAsynchronousServerSocketChannelImpl
|
||||
extends AsynchronousServerSocketChannelImpl implements Iocp.OverlappedChannel
|
||||
{
|
||||
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||
|
||||
// 2 * (sizeof(SOCKET_ADDRESS) + 16)
|
||||
private static final int DATA_BUFFER_SIZE = 88;
|
||||
|
||||
private final long handle;
|
||||
private final int completionKey;
|
||||
private final Iocp iocp;
|
||||
|
||||
// typically there will be zero, or one I/O operations pending. In rare
|
||||
// cases there may be more. These rare cases arise when a sequence of accept
|
||||
// operations complete immediately and handled by the initiating thread.
|
||||
// The corresponding OVERLAPPED cannot be reused/released until the completion
|
||||
// event has been posted.
|
||||
private final PendingIoCache ioCache;
|
||||
|
||||
// the data buffer to receive the local/remote socket address
|
||||
private final long dataBuffer;
|
||||
|
||||
// flag to indicate that an accept operation is outstanding
|
||||
private AtomicBoolean accepting = new AtomicBoolean();
|
||||
|
||||
|
||||
WindowsAsynchronousServerSocketChannelImpl(Iocp iocp) throws IOException {
|
||||
super(iocp);
|
||||
|
||||
// associate socket with given completion port
|
||||
long h = IOUtil.fdVal(fd);
|
||||
int key;
|
||||
try {
|
||||
key = iocp.associate(this, h);
|
||||
} catch (IOException x) {
|
||||
closesocket0(h); // prevent leak
|
||||
throw x;
|
||||
}
|
||||
|
||||
this.handle = h;
|
||||
this.completionKey = key;
|
||||
this.iocp = iocp;
|
||||
this.ioCache = new PendingIoCache();
|
||||
this.dataBuffer = unsafe.allocateMemory(DATA_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V,A> PendingFuture<V,A> getByOverlapped(long overlapped) {
|
||||
return ioCache.remove(overlapped);
|
||||
}
|
||||
|
||||
@Override
|
||||
void implClose() throws IOException {
|
||||
// close socket (which may cause outstanding accept to be aborted).
|
||||
closesocket0(handle);
|
||||
|
||||
// waits until the accept operations have completed
|
||||
ioCache.close();
|
||||
|
||||
// finally disassociate from the completion port
|
||||
iocp.disassociate(completionKey);
|
||||
|
||||
// release other resources
|
||||
unsafe.freeMemory(dataBuffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousChannelGroupImpl group() {
|
||||
return iocp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Task to initiate accept operation and to handle result.
|
||||
*/
|
||||
private class AcceptTask implements Runnable, Iocp.ResultHandler {
|
||||
private final WindowsAsynchronousSocketChannelImpl channel;
|
||||
private final AccessControlContext acc;
|
||||
private final PendingFuture<AsynchronousSocketChannel,Object> result;
|
||||
|
||||
AcceptTask(WindowsAsynchronousSocketChannelImpl channel,
|
||||
AccessControlContext acc,
|
||||
PendingFuture<AsynchronousSocketChannel,Object> result)
|
||||
{
|
||||
this.channel = channel;
|
||||
this.acc = acc;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
void enableAccept() {
|
||||
accepting.set(false);
|
||||
}
|
||||
|
||||
void closeChildChannel() {
|
||||
try {
|
||||
channel.close();
|
||||
} catch (IOException ignore) { }
|
||||
}
|
||||
|
||||
// caller must have acquired read lock for the listener and child channel.
|
||||
void finishAccept() throws IOException {
|
||||
/**
|
||||
* Set local/remote addresses. This is currently very inefficient
|
||||
* in that it requires 2 calls to getsockname and 2 calls to getpeername.
|
||||
* (should change this to use GetAcceptExSockaddrs)
|
||||
*/
|
||||
updateAcceptContext(handle, channel.handle());
|
||||
|
||||
InetSocketAddress local = Net.localAddress(channel.fd);
|
||||
final InetSocketAddress remote = Net.remoteAddress(channel.fd);
|
||||
channel.setConnected(local, remote);
|
||||
|
||||
// permission check (in context of initiating thread)
|
||||
if (acc != null) {
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
sm.checkAccept(remote.getAddress().getHostAddress(),
|
||||
remote.getPort());
|
||||
return null;
|
||||
}
|
||||
}, acc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates the accept operation.
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
long overlapped = 0L;
|
||||
|
||||
try {
|
||||
// begin usage of listener socket
|
||||
begin();
|
||||
try {
|
||||
// begin usage of child socket (as it is registered with
|
||||
// completion port and so may be closed in the event that
|
||||
// the group is forcefully closed).
|
||||
channel.begin();
|
||||
|
||||
synchronized (result) {
|
||||
overlapped = ioCache.add(result);
|
||||
|
||||
int n = accept0(handle, channel.handle(), overlapped, dataBuffer);
|
||||
if (n == IOStatus.UNAVAILABLE) {
|
||||
return;
|
||||
}
|
||||
|
||||
// connection accepted immediately
|
||||
finishAccept();
|
||||
|
||||
// allow another accept before the result is set
|
||||
enableAccept();
|
||||
result.setResult(channel);
|
||||
}
|
||||
} finally {
|
||||
// end usage on child socket
|
||||
channel.end();
|
||||
}
|
||||
} catch (Throwable x) {
|
||||
// failed to initiate accept so release resources
|
||||
if (overlapped != 0L)
|
||||
ioCache.remove(overlapped);
|
||||
closeChildChannel();
|
||||
if (x instanceof ClosedChannelException)
|
||||
x = new AsynchronousCloseException();
|
||||
if (!(x instanceof IOException) && !(x instanceof SecurityException))
|
||||
x = new IOException(x);
|
||||
enableAccept();
|
||||
result.setFailure(x);
|
||||
} finally {
|
||||
// end of usage of listener socket
|
||||
end();
|
||||
}
|
||||
|
||||
// accept completed immediately but may not have executed on
|
||||
// initiating thread in which case the operation may have been
|
||||
// cancelled.
|
||||
if (result.isCancelled()) {
|
||||
closeChildChannel();
|
||||
}
|
||||
|
||||
// invoke completion handler
|
||||
Invoker.invokeIndirectly(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executed when the I/O has completed
|
||||
*/
|
||||
@Override
|
||||
public void completed(int bytesTransferred, boolean canInvokeDirect) {
|
||||
try {
|
||||
// connection accept after group has shutdown
|
||||
if (iocp.isShutdown()) {
|
||||
throw new IOException(new ShutdownChannelGroupException());
|
||||
}
|
||||
|
||||
// finish the accept
|
||||
try {
|
||||
begin();
|
||||
try {
|
||||
channel.begin();
|
||||
finishAccept();
|
||||
} finally {
|
||||
channel.end();
|
||||
}
|
||||
} finally {
|
||||
end();
|
||||
}
|
||||
|
||||
// allow another accept before the result is set
|
||||
enableAccept();
|
||||
result.setResult(channel);
|
||||
} catch (Throwable x) {
|
||||
enableAccept();
|
||||
closeChildChannel();
|
||||
if (x instanceof ClosedChannelException)
|
||||
x = new AsynchronousCloseException();
|
||||
if (!(x instanceof IOException) && !(x instanceof SecurityException))
|
||||
x = new IOException(x);
|
||||
result.setFailure(x);
|
||||
}
|
||||
|
||||
// if an async cancel has already cancelled the operation then
|
||||
// close the new channel so as to free resources
|
||||
if (result.isCancelled()) {
|
||||
closeChildChannel();
|
||||
}
|
||||
|
||||
// invoke handler (but not directly)
|
||||
Invoker.invokeIndirectly(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(int error, IOException x) {
|
||||
enableAccept();
|
||||
closeChildChannel();
|
||||
|
||||
// release waiters
|
||||
if (isOpen()) {
|
||||
result.setFailure(x);
|
||||
} else {
|
||||
result.setFailure(new AsynchronousCloseException());
|
||||
}
|
||||
Invoker.invokeIndirectly(result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Future<AsynchronousSocketChannel> implAccept(Object attachment,
|
||||
final CompletionHandler<AsynchronousSocketChannel,Object> handler)
|
||||
{
|
||||
if (!isOpen()) {
|
||||
Throwable exc = new ClosedChannelException();
|
||||
if (handler == null)
|
||||
return CompletedFuture.withFailure(exc);
|
||||
Invoker.invokeIndirectly(this, handler, attachment, null, exc);
|
||||
return null;
|
||||
}
|
||||
if (isAcceptKilled())
|
||||
throw new RuntimeException("Accept not allowed due to cancellation");
|
||||
|
||||
// ensure channel is bound to local address
|
||||
if (localAddress == null)
|
||||
throw new NotYetBoundException();
|
||||
|
||||
// create the socket that will be accepted. The creation of the socket
|
||||
// is enclosed by a begin/end for the listener socket to ensure that
|
||||
// we check that the listener is open and also to prevent the I/O
|
||||
// port from being closed as the new socket is registered.
|
||||
WindowsAsynchronousSocketChannelImpl ch = null;
|
||||
IOException ioe = null;
|
||||
try {
|
||||
begin();
|
||||
ch = new WindowsAsynchronousSocketChannelImpl(iocp, false);
|
||||
} catch (IOException x) {
|
||||
ioe = x;
|
||||
} finally {
|
||||
end();
|
||||
}
|
||||
if (ioe != null) {
|
||||
if (handler == null)
|
||||
return CompletedFuture.withFailure(ioe);
|
||||
Invoker.invokeIndirectly(this, handler, attachment, null, ioe);
|
||||
return null;
|
||||
}
|
||||
|
||||
// need calling context when there is security manager as
|
||||
// permission check may be done in a different thread without
|
||||
// any application call frames on the stack
|
||||
AccessControlContext acc = (System.getSecurityManager() == null) ?
|
||||
null : AccessController.getContext();
|
||||
|
||||
PendingFuture<AsynchronousSocketChannel,Object> result =
|
||||
new PendingFuture<AsynchronousSocketChannel,Object>(this, handler, attachment);
|
||||
AcceptTask task = new AcceptTask(ch, acc, result);
|
||||
result.setContext(task);
|
||||
|
||||
// check and set flag to prevent concurrent accepting
|
||||
if (!accepting.compareAndSet(false, true))
|
||||
throw new AcceptPendingException();
|
||||
|
||||
// initiate I/O
|
||||
task.run();
|
||||
return result;
|
||||
}
|
||||
|
||||
// -- Native methods --
|
||||
|
||||
private static native void initIDs();
|
||||
|
||||
private static native int accept0(long listenSocket, long acceptSocket,
|
||||
long overlapped, long dataBuffer) throws IOException;
|
||||
|
||||
private static native void updateAcceptContext(long listenSocket,
|
||||
long acceptSocket) throws IOException;
|
||||
|
||||
private static native void closesocket0(long socket) throws IOException;
|
||||
|
||||
static {
|
||||
IOUtil.load();
|
||||
initIDs();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,933 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 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. 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 sun.nio.ch;
|
||||
|
||||
import java.nio.channels.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.net.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.io.IOException;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
/**
|
||||
* Windows implementation of AsynchronousSocketChannel using overlapped I/O.
|
||||
*/
|
||||
|
||||
class WindowsAsynchronousSocketChannelImpl
|
||||
extends AsynchronousSocketChannelImpl implements Iocp.OverlappedChannel
|
||||
{
|
||||
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||
private static int addressSize = unsafe.addressSize();
|
||||
|
||||
private static int dependsArch(int value32, int value64) {
|
||||
return (addressSize == 4) ? value32 : value64;
|
||||
}
|
||||
|
||||
/*
|
||||
* typedef struct _WSABUF {
|
||||
* u_long len;
|
||||
* char FAR * buf;
|
||||
* } WSABUF;
|
||||
*/
|
||||
private static final int SIZEOF_WSABUF = dependsArch(8, 16);
|
||||
private static final int OFFSETOF_LEN = 0;
|
||||
private static final int OFFSETOF_BUF = dependsArch(4, 8);
|
||||
|
||||
// maximum vector size for scatter/gather I/O
|
||||
private static final int MAX_WSABUF = 16;
|
||||
|
||||
private static final int SIZEOF_WSABUFARRAY = MAX_WSABUF * SIZEOF_WSABUF;
|
||||
|
||||
|
||||
// socket handle. Use begin()/end() around each usage of this handle.
|
||||
final long handle;
|
||||
|
||||
// I/O completion port that the socket is associated with
|
||||
private final Iocp iocp;
|
||||
|
||||
// completion key to identify channel when I/O completes
|
||||
private final int completionKey;
|
||||
|
||||
// Pending I/O operations are tied to an OVERLAPPED structure that can only
|
||||
// be released when the I/O completion event is posted to the completion
|
||||
// port. Where I/O operations complete immediately then it is possible
|
||||
// there may be more than two OVERLAPPED structures in use.
|
||||
private final PendingIoCache ioCache;
|
||||
|
||||
// per-channel arrays of WSABUF structures
|
||||
private final long readBufferArray;
|
||||
private final long writeBufferArray;
|
||||
|
||||
|
||||
WindowsAsynchronousSocketChannelImpl(Iocp iocp, boolean failIfGroupShutdown)
|
||||
throws IOException
|
||||
{
|
||||
super(iocp);
|
||||
|
||||
// associate socket with default completion port
|
||||
long h = IOUtil.fdVal(fd);
|
||||
int key = 0;
|
||||
try {
|
||||
key = iocp.associate(this, h);
|
||||
} catch (ShutdownChannelGroupException x) {
|
||||
if (failIfGroupShutdown) {
|
||||
closesocket0(h);
|
||||
throw x;
|
||||
}
|
||||
} catch (IOException x) {
|
||||
closesocket0(h);
|
||||
throw x;
|
||||
}
|
||||
|
||||
this.handle = h;
|
||||
this.iocp = iocp;
|
||||
this.completionKey = key;
|
||||
this.ioCache = new PendingIoCache();
|
||||
|
||||
// allocate WSABUF arrays
|
||||
this.readBufferArray = unsafe.allocateMemory(SIZEOF_WSABUFARRAY);
|
||||
this.writeBufferArray = unsafe.allocateMemory(SIZEOF_WSABUFARRAY);
|
||||
}
|
||||
|
||||
WindowsAsynchronousSocketChannelImpl(Iocp iocp) throws IOException {
|
||||
this(iocp, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousChannelGroupImpl group() {
|
||||
return iocp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked by Iocp when an I/O operation competes.
|
||||
*/
|
||||
@Override
|
||||
public <V,A> PendingFuture<V,A> getByOverlapped(long overlapped) {
|
||||
return ioCache.remove(overlapped);
|
||||
}
|
||||
|
||||
// invoked by WindowsAsynchronousServerSocketChannelImpl
|
||||
long handle() {
|
||||
return handle;
|
||||
}
|
||||
|
||||
// invoked by WindowsAsynchronousServerSocketChannelImpl when new connection
|
||||
// accept
|
||||
void setConnected(InetSocketAddress localAddress,
|
||||
InetSocketAddress remoteAddress)
|
||||
{
|
||||
synchronized (stateLock) {
|
||||
state = ST_CONNECTED;
|
||||
this.localAddress = localAddress;
|
||||
this.remoteAddress = remoteAddress;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void implClose() throws IOException {
|
||||
// close socket (may cause outstanding async I/O operations to fail).
|
||||
closesocket0(handle);
|
||||
|
||||
// waits until all I/O operations have completed
|
||||
ioCache.close();
|
||||
|
||||
// release arrays of WSABUF structures
|
||||
unsafe.freeMemory(readBufferArray);
|
||||
unsafe.freeMemory(writeBufferArray);
|
||||
|
||||
// finally disassociate from the completion port (key can be 0 if
|
||||
// channel created when group is shutdown)
|
||||
if (completionKey != 0)
|
||||
iocp.disassociate(completionKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel(PendingFuture<?,?> task) {
|
||||
if (task.getContext() instanceof ConnectTask)
|
||||
killConnect();
|
||||
if (task.getContext() instanceof ReadTask)
|
||||
killReading();
|
||||
if (task.getContext() instanceof WriteTask)
|
||||
killWriting();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the task to initiate a connection and the handler to
|
||||
* consume the result when the connection is established (or fails).
|
||||
*/
|
||||
private class ConnectTask<A> implements Runnable, Iocp.ResultHandler {
|
||||
private final InetSocketAddress remote;
|
||||
private final PendingFuture<Void,A> result;
|
||||
|
||||
ConnectTask(InetSocketAddress remote, PendingFuture<Void,A> result) {
|
||||
this.remote = remote;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
private void closeChannel() {
|
||||
try {
|
||||
close();
|
||||
} catch (IOException ignore) { }
|
||||
}
|
||||
|
||||
private IOException toIOException(Throwable x) {
|
||||
if (x instanceof IOException) {
|
||||
if (x instanceof ClosedChannelException)
|
||||
x = new AsynchronousCloseException();
|
||||
return (IOException)x;
|
||||
}
|
||||
return new IOException(x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke after a connection is successfully established.
|
||||
*/
|
||||
private void afterConnect() throws IOException {
|
||||
updateConnectContext(handle);
|
||||
synchronized (stateLock) {
|
||||
state = ST_CONNECTED;
|
||||
remoteAddress = remote;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Task to initiate a connection.
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
long overlapped = 0L;
|
||||
Throwable exc = null;
|
||||
try {
|
||||
begin();
|
||||
|
||||
// synchronize on result to allow this thread handle the case
|
||||
// where the connection is established immediately.
|
||||
synchronized (result) {
|
||||
overlapped = ioCache.add(result);
|
||||
// initiate the connection
|
||||
int n = connect0(handle, Net.isIPv6Available(), remote.getAddress(),
|
||||
remote.getPort(), overlapped);
|
||||
if (n == IOStatus.UNAVAILABLE) {
|
||||
// connection is pending
|
||||
return;
|
||||
}
|
||||
|
||||
// connection established immediately
|
||||
afterConnect();
|
||||
result.setResult(null);
|
||||
}
|
||||
} catch (Throwable x) {
|
||||
if (overlapped != 0L)
|
||||
ioCache.remove(overlapped);
|
||||
exc = x;
|
||||
} finally {
|
||||
end();
|
||||
}
|
||||
|
||||
if (exc != null) {
|
||||
closeChannel();
|
||||
result.setFailure(toIOException(exc));
|
||||
}
|
||||
Invoker.invoke(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked by handler thread when connection established.
|
||||
*/
|
||||
@Override
|
||||
public void completed(int bytesTransferred, boolean canInvokeDirect) {
|
||||
Throwable exc = null;
|
||||
try {
|
||||
begin();
|
||||
afterConnect();
|
||||
result.setResult(null);
|
||||
} catch (Throwable x) {
|
||||
// channel is closed or unable to finish connect
|
||||
exc = x;
|
||||
} finally {
|
||||
end();
|
||||
}
|
||||
|
||||
// can't close channel while in begin/end block
|
||||
if (exc != null) {
|
||||
closeChannel();
|
||||
result.setFailure(toIOException(exc));
|
||||
}
|
||||
|
||||
if (canInvokeDirect) {
|
||||
Invoker.invokeUnchecked(result);
|
||||
} else {
|
||||
Invoker.invoke(result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked by handler thread when failed to establish connection.
|
||||
*/
|
||||
@Override
|
||||
public void failed(int error, IOException x) {
|
||||
if (isOpen()) {
|
||||
closeChannel();
|
||||
result.setFailure(x);
|
||||
} else {
|
||||
result.setFailure(new AsynchronousCloseException());
|
||||
}
|
||||
Invoker.invoke(result);
|
||||
}
|
||||
}
|
||||
|
||||
private void doPrivilegedBind(final SocketAddress sa) throws IOException {
|
||||
try {
|
||||
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
|
||||
public Void run() throws IOException {
|
||||
bind(sa);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
} catch (PrivilegedActionException e) {
|
||||
throw (IOException) e.getException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
<A> Future<Void> implConnect(SocketAddress remote,
|
||||
A attachment,
|
||||
CompletionHandler<Void,? super A> handler)
|
||||
{
|
||||
if (!isOpen()) {
|
||||
Throwable exc = new ClosedChannelException();
|
||||
if (handler == null)
|
||||
return CompletedFuture.withFailure(exc);
|
||||
Invoker.invoke(this, handler, attachment, null, exc);
|
||||
return null;
|
||||
}
|
||||
|
||||
InetSocketAddress isa = Net.checkAddress(remote);
|
||||
|
||||
// permission check
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null)
|
||||
sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort());
|
||||
|
||||
// check and update state
|
||||
// ConnectEx requires the socket to be bound to a local address
|
||||
IOException bindException = null;
|
||||
synchronized (stateLock) {
|
||||
if (state == ST_CONNECTED)
|
||||
throw new AlreadyConnectedException();
|
||||
if (state == ST_PENDING)
|
||||
throw new ConnectionPendingException();
|
||||
if (localAddress == null) {
|
||||
try {
|
||||
SocketAddress any = new InetSocketAddress(0);
|
||||
if (sm == null) {
|
||||
bind(any);
|
||||
} else {
|
||||
doPrivilegedBind(any);
|
||||
}
|
||||
} catch (IOException x) {
|
||||
bindException = x;
|
||||
}
|
||||
}
|
||||
if (bindException == null)
|
||||
state = ST_PENDING;
|
||||
}
|
||||
|
||||
// handle bind failure
|
||||
if (bindException != null) {
|
||||
try {
|
||||
close();
|
||||
} catch (IOException ignore) { }
|
||||
if (handler == null)
|
||||
return CompletedFuture.withFailure(bindException);
|
||||
Invoker.invoke(this, handler, attachment, null, bindException);
|
||||
return null;
|
||||
}
|
||||
|
||||
// setup task
|
||||
PendingFuture<Void,A> result =
|
||||
new PendingFuture<Void,A>(this, handler, attachment);
|
||||
ConnectTask<A> task = new ConnectTask<A>(isa, result);
|
||||
result.setContext(task);
|
||||
|
||||
// initiate I/O
|
||||
task.run();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the task to initiate a read and the handler to consume the
|
||||
* result when the read completes.
|
||||
*/
|
||||
private class ReadTask<V,A> implements Runnable, Iocp.ResultHandler {
|
||||
private final ByteBuffer[] bufs;
|
||||
private final int numBufs;
|
||||
private final boolean scatteringRead;
|
||||
private final PendingFuture<V,A> result;
|
||||
|
||||
// set by run method
|
||||
private ByteBuffer[] shadow;
|
||||
|
||||
ReadTask(ByteBuffer[] bufs,
|
||||
boolean scatteringRead,
|
||||
PendingFuture<V,A> result)
|
||||
{
|
||||
this.bufs = bufs;
|
||||
this.numBufs = (bufs.length > MAX_WSABUF) ? MAX_WSABUF : bufs.length;
|
||||
this.scatteringRead = scatteringRead;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked prior to read to prepare the WSABUF array. Where necessary,
|
||||
* it substitutes non-direct buffers with direct buffers.
|
||||
*/
|
||||
void prepareBuffers() {
|
||||
shadow = new ByteBuffer[numBufs];
|
||||
long address = readBufferArray;
|
||||
for (int i=0; i<numBufs; i++) {
|
||||
ByteBuffer dst = bufs[i];
|
||||
int pos = dst.position();
|
||||
int lim = dst.limit();
|
||||
assert (pos <= lim);
|
||||
int rem = (pos <= lim ? lim - pos : 0);
|
||||
long a;
|
||||
if (!(dst instanceof DirectBuffer)) {
|
||||
// substitute with direct buffer
|
||||
ByteBuffer bb = Util.getTemporaryDirectBuffer(rem);
|
||||
shadow[i] = bb;
|
||||
a = ((DirectBuffer)bb).address();
|
||||
} else {
|
||||
shadow[i] = dst;
|
||||
a = ((DirectBuffer)dst).address() + pos;
|
||||
}
|
||||
unsafe.putAddress(address + OFFSETOF_BUF, a);
|
||||
unsafe.putInt(address + OFFSETOF_LEN, rem);
|
||||
address += SIZEOF_WSABUF;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked after a read has completed to update the buffer positions
|
||||
* and release any substituted buffers.
|
||||
*/
|
||||
void updateBuffers(int bytesRead) {
|
||||
for (int i=0; i<numBufs; i++) {
|
||||
ByteBuffer nextBuffer = shadow[i];
|
||||
int pos = nextBuffer.position();
|
||||
int len = nextBuffer.remaining();
|
||||
if (bytesRead >= len) {
|
||||
bytesRead -= len;
|
||||
int newPosition = pos + len;
|
||||
try {
|
||||
nextBuffer.position(newPosition);
|
||||
} catch (IllegalArgumentException x) {
|
||||
// position changed by another
|
||||
}
|
||||
} else { // Buffers not completely filled
|
||||
if (bytesRead > 0) {
|
||||
assert(pos + bytesRead < (long)Integer.MAX_VALUE);
|
||||
int newPosition = pos + bytesRead;
|
||||
try {
|
||||
nextBuffer.position(newPosition);
|
||||
} catch (IllegalArgumentException x) {
|
||||
// position changed by another
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Put results from shadow into the slow buffers
|
||||
for (int i=0; i<numBufs; i++) {
|
||||
if (!(bufs[i] instanceof DirectBuffer)) {
|
||||
shadow[i].flip();
|
||||
try {
|
||||
bufs[i].put(shadow[i]);
|
||||
} catch (BufferOverflowException x) {
|
||||
// position changed by another
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void releaseBuffers() {
|
||||
for (int i=0; i<numBufs; i++) {
|
||||
if (!(bufs[i] instanceof DirectBuffer)) {
|
||||
Util.releaseTemporaryDirectBuffer(shadow[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void run() {
|
||||
long overlapped = 0L;
|
||||
boolean prepared = false;
|
||||
boolean pending = false;
|
||||
|
||||
try {
|
||||
begin();
|
||||
|
||||
// substitute non-direct buffers
|
||||
prepareBuffers();
|
||||
prepared = true;
|
||||
|
||||
// get an OVERLAPPED structure (from the cache or allocate)
|
||||
overlapped = ioCache.add(result);
|
||||
|
||||
// initiate read
|
||||
int n = read0(handle, numBufs, readBufferArray, overlapped);
|
||||
if (n == IOStatus.UNAVAILABLE) {
|
||||
// I/O is pending
|
||||
pending = true;
|
||||
return;
|
||||
}
|
||||
if (n == IOStatus.EOF) {
|
||||
// input shutdown
|
||||
enableReading();
|
||||
if (scatteringRead) {
|
||||
result.setResult((V)Long.valueOf(-1L));
|
||||
} else {
|
||||
result.setResult((V)Integer.valueOf(-1));
|
||||
}
|
||||
} else {
|
||||
throw new InternalError("Read completed immediately");
|
||||
}
|
||||
} catch (Throwable x) {
|
||||
// failed to initiate read
|
||||
// reset read flag before releasing waiters
|
||||
enableReading();
|
||||
if (x instanceof ClosedChannelException)
|
||||
x = new AsynchronousCloseException();
|
||||
if (!(x instanceof IOException))
|
||||
x = new IOException(x);
|
||||
result.setFailure(x);
|
||||
} finally {
|
||||
// release resources if I/O not pending
|
||||
if (!pending) {
|
||||
if (overlapped != 0L)
|
||||
ioCache.remove(overlapped);
|
||||
if (prepared)
|
||||
releaseBuffers();
|
||||
}
|
||||
end();
|
||||
}
|
||||
|
||||
// invoke completion handler
|
||||
Invoker.invoke(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executed when the I/O has completed
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void completed(int bytesTransferred, boolean canInvokeDirect) {
|
||||
if (bytesTransferred == 0) {
|
||||
bytesTransferred = -1; // EOF
|
||||
} else {
|
||||
updateBuffers(bytesTransferred);
|
||||
}
|
||||
|
||||
// return direct buffer to cache if substituted
|
||||
releaseBuffers();
|
||||
|
||||
// release waiters if not already released by timeout
|
||||
synchronized (result) {
|
||||
if (result.isDone())
|
||||
return;
|
||||
enableReading();
|
||||
if (scatteringRead) {
|
||||
result.setResult((V)Long.valueOf(bytesTransferred));
|
||||
} else {
|
||||
result.setResult((V)Integer.valueOf(bytesTransferred));
|
||||
}
|
||||
}
|
||||
if (canInvokeDirect) {
|
||||
Invoker.invokeUnchecked(result);
|
||||
} else {
|
||||
Invoker.invoke(result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(int error, IOException x) {
|
||||
// return direct buffer to cache if substituted
|
||||
releaseBuffers();
|
||||
|
||||
// release waiters if not already released by timeout
|
||||
if (!isOpen())
|
||||
x = new AsynchronousCloseException();
|
||||
|
||||
synchronized (result) {
|
||||
if (result.isDone())
|
||||
return;
|
||||
enableReading();
|
||||
result.setFailure(x);
|
||||
}
|
||||
Invoker.invoke(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked if timeout expires before it is cancelled
|
||||
*/
|
||||
void timeout() {
|
||||
// synchronize on result as the I/O could complete/fail
|
||||
synchronized (result) {
|
||||
if (result.isDone())
|
||||
return;
|
||||
|
||||
// kill further reading before releasing waiters
|
||||
enableReading(true);
|
||||
result.setFailure(new InterruptedByTimeoutException());
|
||||
}
|
||||
|
||||
// invoke handler without any locks
|
||||
Invoker.invoke(result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
<V extends Number,A> Future<V> implRead(boolean isScatteringRead,
|
||||
ByteBuffer dst,
|
||||
ByteBuffer[] dsts,
|
||||
long timeout,
|
||||
TimeUnit unit,
|
||||
A attachment,
|
||||
CompletionHandler<V,? super A> handler)
|
||||
{
|
||||
// setup task
|
||||
PendingFuture<V,A> result =
|
||||
new PendingFuture<V,A>(this, handler, attachment);
|
||||
ByteBuffer[] bufs;
|
||||
if (isScatteringRead) {
|
||||
bufs = dsts;
|
||||
} else {
|
||||
bufs = new ByteBuffer[1];
|
||||
bufs[0] = dst;
|
||||
}
|
||||
final ReadTask<V,A> readTask =
|
||||
new ReadTask<V,A>(bufs, isScatteringRead, result);
|
||||
result.setContext(readTask);
|
||||
|
||||
// schedule timeout
|
||||
if (timeout > 0L) {
|
||||
Future<?> timeoutTask = iocp.schedule(new Runnable() {
|
||||
public void run() {
|
||||
readTask.timeout();
|
||||
}
|
||||
}, timeout, unit);
|
||||
result.setTimeoutTask(timeoutTask);
|
||||
}
|
||||
|
||||
// initiate I/O
|
||||
readTask.run();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the task to initiate a write and the handler to consume the
|
||||
* result when the write completes.
|
||||
*/
|
||||
private class WriteTask<V,A> implements Runnable, Iocp.ResultHandler {
|
||||
private final ByteBuffer[] bufs;
|
||||
private final int numBufs;
|
||||
private final boolean gatheringWrite;
|
||||
private final PendingFuture<V,A> result;
|
||||
|
||||
// set by run method
|
||||
private ByteBuffer[] shadow;
|
||||
|
||||
WriteTask(ByteBuffer[] bufs,
|
||||
boolean gatheringWrite,
|
||||
PendingFuture<V,A> result)
|
||||
{
|
||||
this.bufs = bufs;
|
||||
this.numBufs = (bufs.length > MAX_WSABUF) ? MAX_WSABUF : bufs.length;
|
||||
this.gatheringWrite = gatheringWrite;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked prior to write to prepare the WSABUF array. Where necessary,
|
||||
* it substitutes non-direct buffers with direct buffers.
|
||||
*/
|
||||
void prepareBuffers() {
|
||||
shadow = new ByteBuffer[numBufs];
|
||||
long address = writeBufferArray;
|
||||
for (int i=0; i<numBufs; i++) {
|
||||
ByteBuffer src = bufs[i];
|
||||
int pos = src.position();
|
||||
int lim = src.limit();
|
||||
assert (pos <= lim);
|
||||
int rem = (pos <= lim ? lim - pos : 0);
|
||||
long a;
|
||||
if (!(src instanceof DirectBuffer)) {
|
||||
// substitute with direct buffer
|
||||
ByteBuffer bb = Util.getTemporaryDirectBuffer(rem);
|
||||
bb.put(src);
|
||||
bb.flip();
|
||||
src.position(pos); // leave heap buffer untouched for now
|
||||
shadow[i] = bb;
|
||||
a = ((DirectBuffer)bb).address();
|
||||
} else {
|
||||
shadow[i] = src;
|
||||
a = ((DirectBuffer)src).address() + pos;
|
||||
}
|
||||
unsafe.putAddress(address + OFFSETOF_BUF, a);
|
||||
unsafe.putInt(address + OFFSETOF_LEN, rem);
|
||||
address += SIZEOF_WSABUF;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked after a write has completed to update the buffer positions
|
||||
* and release any substituted buffers.
|
||||
*/
|
||||
void updateBuffers(int bytesWritten) {
|
||||
// Notify the buffers how many bytes were taken
|
||||
for (int i=0; i<numBufs; i++) {
|
||||
ByteBuffer nextBuffer = bufs[i];
|
||||
int pos = nextBuffer.position();
|
||||
int lim = nextBuffer.limit();
|
||||
int len = (pos <= lim ? lim - pos : lim);
|
||||
if (bytesWritten >= len) {
|
||||
bytesWritten -= len;
|
||||
int newPosition = pos + len;
|
||||
try {
|
||||
nextBuffer.position(newPosition);
|
||||
} catch (IllegalArgumentException x) {
|
||||
// position changed by someone else
|
||||
}
|
||||
} else { // Buffers not completely filled
|
||||
if (bytesWritten > 0) {
|
||||
assert(pos + bytesWritten < (long)Integer.MAX_VALUE);
|
||||
int newPosition = pos + bytesWritten;
|
||||
try {
|
||||
nextBuffer.position(newPosition);
|
||||
} catch (IllegalArgumentException x) {
|
||||
// position changed by someone else
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void releaseBuffers() {
|
||||
for (int i=0; i<numBufs; i++) {
|
||||
if (!(bufs[i] instanceof DirectBuffer)) {
|
||||
Util.releaseTemporaryDirectBuffer(shadow[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
//@SuppressWarnings("unchecked")
|
||||
public void run() {
|
||||
long overlapped = 0L;
|
||||
boolean prepared = false;
|
||||
boolean pending = false;
|
||||
boolean shutdown = false;
|
||||
|
||||
try {
|
||||
begin();
|
||||
|
||||
// substitute non-direct buffers
|
||||
prepareBuffers();
|
||||
prepared = true;
|
||||
|
||||
// get an OVERLAPPED structure (from the cache or allocate)
|
||||
overlapped = ioCache.add(result);
|
||||
int n = write0(handle, numBufs, writeBufferArray, overlapped);
|
||||
if (n == IOStatus.UNAVAILABLE) {
|
||||
// I/O is pending
|
||||
pending = true;
|
||||
return;
|
||||
}
|
||||
if (n == IOStatus.EOF) {
|
||||
// special case for shutdown output
|
||||
shutdown = true;
|
||||
throw new ClosedChannelException();
|
||||
}
|
||||
// write completed immediately
|
||||
throw new InternalError("Write completed immediately");
|
||||
} catch (Throwable x) {
|
||||
// write failed. Enable writing before releasing waiters.
|
||||
enableWriting();
|
||||
if (!shutdown && (x instanceof ClosedChannelException))
|
||||
x = new AsynchronousCloseException();
|
||||
if (!(x instanceof IOException))
|
||||
x = new IOException(x);
|
||||
result.setFailure(x);
|
||||
} finally {
|
||||
// release resources if I/O not pending
|
||||
if (!pending) {
|
||||
if (overlapped != 0L)
|
||||
ioCache.remove(overlapped);
|
||||
if (prepared)
|
||||
releaseBuffers();
|
||||
}
|
||||
end();
|
||||
}
|
||||
|
||||
// invoke completion handler
|
||||
Invoker.invoke(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executed when the I/O has completed
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void completed(int bytesTransferred, boolean canInvokeDirect) {
|
||||
updateBuffers(bytesTransferred);
|
||||
|
||||
// return direct buffer to cache if substituted
|
||||
releaseBuffers();
|
||||
|
||||
// release waiters if not already released by timeout
|
||||
synchronized (result) {
|
||||
if (result.isDone())
|
||||
return;
|
||||
enableWriting();
|
||||
if (gatheringWrite) {
|
||||
result.setResult((V)Long.valueOf(bytesTransferred));
|
||||
} else {
|
||||
result.setResult((V)Integer.valueOf(bytesTransferred));
|
||||
}
|
||||
}
|
||||
if (canInvokeDirect) {
|
||||
Invoker.invokeUnchecked(result);
|
||||
} else {
|
||||
Invoker.invoke(result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(int error, IOException x) {
|
||||
// return direct buffer to cache if substituted
|
||||
releaseBuffers();
|
||||
|
||||
// release waiters if not already released by timeout
|
||||
if (!isOpen())
|
||||
x = new AsynchronousCloseException();
|
||||
|
||||
synchronized (result) {
|
||||
if (result.isDone())
|
||||
return;
|
||||
enableWriting();
|
||||
result.setFailure(x);
|
||||
}
|
||||
Invoker.invoke(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked if timeout expires before it is cancelled
|
||||
*/
|
||||
void timeout() {
|
||||
// synchronize on result as the I/O could complete/fail
|
||||
synchronized (result) {
|
||||
if (result.isDone())
|
||||
return;
|
||||
|
||||
// kill further writing before releasing waiters
|
||||
enableWriting(true);
|
||||
result.setFailure(new InterruptedByTimeoutException());
|
||||
}
|
||||
|
||||
// invoke handler without any locks
|
||||
Invoker.invoke(result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
<V extends Number,A> Future<V> implWrite(boolean gatheringWrite,
|
||||
ByteBuffer src,
|
||||
ByteBuffer[] srcs,
|
||||
long timeout,
|
||||
TimeUnit unit,
|
||||
A attachment,
|
||||
CompletionHandler<V,? super A> handler)
|
||||
{
|
||||
// setup task
|
||||
PendingFuture<V,A> result =
|
||||
new PendingFuture<V,A>(this, handler, attachment);
|
||||
ByteBuffer[] bufs;
|
||||
if (gatheringWrite) {
|
||||
bufs = srcs;
|
||||
} else {
|
||||
bufs = new ByteBuffer[1];
|
||||
bufs[0] = src;
|
||||
}
|
||||
final WriteTask<V,A> writeTask =
|
||||
new WriteTask<V,A>(bufs, gatheringWrite, result);
|
||||
result.setContext(writeTask);
|
||||
|
||||
// schedule timeout
|
||||
if (timeout > 0L) {
|
||||
Future<?> timeoutTask = iocp.schedule(new Runnable() {
|
||||
public void run() {
|
||||
writeTask.timeout();
|
||||
}
|
||||
}, timeout, unit);
|
||||
result.setTimeoutTask(timeoutTask);
|
||||
}
|
||||
|
||||
// initiate I/O
|
||||
writeTask.run();
|
||||
return result;
|
||||
}
|
||||
|
||||
// -- Native methods --
|
||||
|
||||
private static native void initIDs();
|
||||
|
||||
private static native int connect0(long socket, boolean preferIPv6,
|
||||
InetAddress remote, int remotePort, long overlapped) throws IOException;
|
||||
|
||||
private static native void updateConnectContext(long socket) throws IOException;
|
||||
|
||||
private static native int read0(long socket, int count, long addres, long overlapped)
|
||||
throws IOException;
|
||||
|
||||
private static native int write0(long socket, int count, long address,
|
||||
long overlapped) throws IOException;
|
||||
|
||||
private static native void shutdown0(long socket, int how) throws IOException;
|
||||
|
||||
private static native void closesocket0(long socket) throws IOException;
|
||||
|
||||
static {
|
||||
IOUtil.load();
|
||||
initIDs();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,617 @@
|
|||
/*
|
||||
* Copyright (c) 2002, 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. 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 sun.nio.ch;
|
||||
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.ClosedSelectorException;
|
||||
import java.nio.channels.Pipe;
|
||||
import java.nio.channels.SelectableChannel;
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.CancelledKeyException;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* A multi-threaded implementation of Selector for Windows.
|
||||
*
|
||||
* @author Konstantin Kladko
|
||||
* @author Mark Reinhold
|
||||
*/
|
||||
|
||||
final class WindowsSelectorImpl extends SelectorImpl {
|
||||
// Initial capacity of the poll array
|
||||
private final int INIT_CAP = 8;
|
||||
// Maximum number of sockets for select().
|
||||
// Should be INIT_CAP times a power of 2
|
||||
private static final int MAX_SELECTABLE_FDS = 1024;
|
||||
|
||||
// The list of SelectableChannels serviced by this Selector. Every mod
|
||||
// MAX_SELECTABLE_FDS entry is bogus, to align this array with the poll
|
||||
// array, where the corresponding entry is occupied by the wakeupSocket
|
||||
private SelectionKeyImpl[] channelArray = new SelectionKeyImpl[INIT_CAP];
|
||||
|
||||
// The global native poll array holds file decriptors and event masks
|
||||
private PollArrayWrapper pollWrapper;
|
||||
|
||||
// The number of valid entries in poll array, including entries occupied
|
||||
// by wakeup socket handle.
|
||||
private int totalChannels = 1;
|
||||
|
||||
// Number of helper threads needed for select. We need one thread per
|
||||
// each additional set of MAX_SELECTABLE_FDS - 1 channels.
|
||||
private int threadsCount = 0;
|
||||
|
||||
// A list of helper threads for select.
|
||||
private final List<SelectThread> threads = new ArrayList<SelectThread>();
|
||||
|
||||
//Pipe used as a wakeup object.
|
||||
private final Pipe wakeupPipe;
|
||||
|
||||
// File descriptors corresponding to source and sink
|
||||
private final int wakeupSourceFd, wakeupSinkFd;
|
||||
|
||||
// Lock for close cleanup
|
||||
private Object closeLock = new Object();
|
||||
|
||||
// Maps file descriptors to their indices in pollArray
|
||||
private static final class FdMap extends HashMap<Integer, MapEntry> {
|
||||
static final long serialVersionUID = 0L;
|
||||
private MapEntry get(int desc) {
|
||||
return get(Integer.valueOf(desc));
|
||||
}
|
||||
private MapEntry put(SelectionKeyImpl ski) {
|
||||
return put(Integer.valueOf(ski.channel.getFDVal()), new MapEntry(ski));
|
||||
}
|
||||
private MapEntry remove(SelectionKeyImpl ski) {
|
||||
Integer fd = Integer.valueOf(ski.channel.getFDVal());
|
||||
MapEntry x = get(fd);
|
||||
if ((x != null) && (x.ski.channel == ski.channel))
|
||||
return remove(fd);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// class for fdMap entries
|
||||
private static final class MapEntry {
|
||||
SelectionKeyImpl ski;
|
||||
long updateCount = 0;
|
||||
long clearedCount = 0;
|
||||
MapEntry(SelectionKeyImpl ski) {
|
||||
this.ski = ski;
|
||||
}
|
||||
}
|
||||
private final FdMap fdMap = new FdMap();
|
||||
|
||||
// SubSelector for the main thread
|
||||
private final SubSelector subSelector = new SubSelector();
|
||||
|
||||
private long timeout; //timeout for poll
|
||||
|
||||
// Lock for interrupt triggering and clearing
|
||||
private final Object interruptLock = new Object();
|
||||
private volatile boolean interruptTriggered;
|
||||
|
||||
WindowsSelectorImpl(SelectorProvider sp) throws IOException {
|
||||
super(sp);
|
||||
pollWrapper = new PollArrayWrapper(INIT_CAP);
|
||||
wakeupPipe = Pipe.open();
|
||||
wakeupSourceFd = ((SelChImpl)wakeupPipe.source()).getFDVal();
|
||||
|
||||
// Disable the Nagle algorithm so that the wakeup is more immediate
|
||||
SinkChannelImpl sink = (SinkChannelImpl)wakeupPipe.sink();
|
||||
(sink.sc).socket().setTcpNoDelay(true);
|
||||
wakeupSinkFd = ((SelChImpl)sink).getFDVal();
|
||||
|
||||
pollWrapper.addWakeupSocket(wakeupSourceFd, 0);
|
||||
}
|
||||
|
||||
protected int doSelect(long timeout) throws IOException {
|
||||
if (channelArray == null)
|
||||
throw new ClosedSelectorException();
|
||||
this.timeout = timeout; // set selector timeout
|
||||
processDeregisterQueue();
|
||||
if (interruptTriggered) {
|
||||
resetWakeupSocket();
|
||||
return 0;
|
||||
}
|
||||
// Calculate number of helper threads needed for poll. If necessary
|
||||
// threads are created here and start waiting on startLock
|
||||
adjustThreadsCount();
|
||||
finishLock.reset(); // reset finishLock
|
||||
// Wakeup helper threads, waiting on startLock, so they start polling.
|
||||
// Redundant threads will exit here after wakeup.
|
||||
startLock.startThreads();
|
||||
// do polling in the main thread. Main thread is responsible for
|
||||
// first MAX_SELECTABLE_FDS entries in pollArray.
|
||||
try {
|
||||
begin();
|
||||
try {
|
||||
subSelector.poll();
|
||||
} catch (IOException e) {
|
||||
finishLock.setException(e); // Save this exception
|
||||
}
|
||||
// Main thread is out of poll(). Wakeup others and wait for them
|
||||
if (threads.size() > 0)
|
||||
finishLock.waitForHelperThreads();
|
||||
} finally {
|
||||
end();
|
||||
}
|
||||
// Done with poll(). Set wakeupSocket to nonsignaled for the next run.
|
||||
finishLock.checkForException();
|
||||
processDeregisterQueue();
|
||||
int updated = updateSelectedKeys();
|
||||
// Done with poll(). Set wakeupSocket to nonsignaled for the next run.
|
||||
resetWakeupSocket();
|
||||
return updated;
|
||||
}
|
||||
|
||||
// Helper threads wait on this lock for the next poll.
|
||||
private final StartLock startLock = new StartLock();
|
||||
|
||||
private final class StartLock {
|
||||
// A variable which distinguishes the current run of doSelect from the
|
||||
// previous one. Incrementing runsCounter and notifying threads will
|
||||
// trigger another round of poll.
|
||||
private long runsCounter;
|
||||
// Triggers threads, waiting on this lock to start polling.
|
||||
private synchronized void startThreads() {
|
||||
runsCounter++; // next run
|
||||
notifyAll(); // wake up threads.
|
||||
}
|
||||
// This function is called by a helper thread to wait for the
|
||||
// next round of poll(). It also checks, if this thread became
|
||||
// redundant. If yes, it returns true, notifying the thread
|
||||
// that it should exit.
|
||||
private synchronized boolean waitForStart(SelectThread thread) {
|
||||
while (true) {
|
||||
while (runsCounter == thread.lastRun) {
|
||||
try {
|
||||
startLock.wait();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
if (thread.isZombie()) { // redundant thread
|
||||
return true; // will cause run() to exit.
|
||||
} else {
|
||||
thread.lastRun = runsCounter; // update lastRun
|
||||
return false; // will cause run() to poll.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Main thread waits on this lock, until all helper threads are done
|
||||
// with poll().
|
||||
private final FinishLock finishLock = new FinishLock();
|
||||
|
||||
private final class FinishLock {
|
||||
// Number of helper threads, that did not finish yet.
|
||||
private int threadsToFinish;
|
||||
|
||||
// IOException which occurred during the last run.
|
||||
IOException exception = null;
|
||||
|
||||
// Called before polling.
|
||||
private void reset() {
|
||||
threadsToFinish = threads.size(); // helper threads
|
||||
}
|
||||
|
||||
// Each helper thread invokes this function on finishLock, when
|
||||
// the thread is done with poll().
|
||||
private synchronized void threadFinished() {
|
||||
if (threadsToFinish == threads.size()) { // finished poll() first
|
||||
// if finished first, wakeup others
|
||||
wakeup();
|
||||
}
|
||||
threadsToFinish--;
|
||||
if (threadsToFinish == 0) // all helper threads finished poll().
|
||||
notify(); // notify the main thread
|
||||
}
|
||||
|
||||
// The main thread invokes this function on finishLock to wait
|
||||
// for helper threads to finish poll().
|
||||
private synchronized void waitForHelperThreads() {
|
||||
if (threadsToFinish == threads.size()) {
|
||||
// no helper threads finished yet. Wakeup them up.
|
||||
wakeup();
|
||||
}
|
||||
while (threadsToFinish != 0) {
|
||||
try {
|
||||
finishLock.wait();
|
||||
} catch (InterruptedException e) {
|
||||
// Interrupted - set interrupted state.
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sets IOException for this run
|
||||
private synchronized void setException(IOException e) {
|
||||
exception = e;
|
||||
}
|
||||
|
||||
// Checks if there was any exception during the last run.
|
||||
// If yes, throws it
|
||||
private void checkForException() throws IOException {
|
||||
if (exception == null)
|
||||
return;
|
||||
StringBuffer message = new StringBuffer("An exception occurred" +
|
||||
" during the execution of select(): \n");
|
||||
message.append(exception);
|
||||
message.append('\n');
|
||||
exception = null;
|
||||
throw new IOException(message.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private final class SubSelector {
|
||||
private final int pollArrayIndex; // starting index in pollArray to poll
|
||||
// These arrays will hold result of native select().
|
||||
// The first element of each array is the number of selected sockets.
|
||||
// Other elements are file descriptors of selected sockets.
|
||||
private final int[] readFds = new int [MAX_SELECTABLE_FDS + 1];
|
||||
private final int[] writeFds = new int [MAX_SELECTABLE_FDS + 1];
|
||||
private final int[] exceptFds = new int [MAX_SELECTABLE_FDS + 1];
|
||||
|
||||
private SubSelector() {
|
||||
this.pollArrayIndex = 0; // main thread
|
||||
}
|
||||
|
||||
private SubSelector(int threadIndex) { // helper threads
|
||||
this.pollArrayIndex = (threadIndex + 1) * MAX_SELECTABLE_FDS;
|
||||
}
|
||||
|
||||
private int poll() throws IOException{ // poll for the main thread
|
||||
return poll0(pollWrapper.pollArrayAddress,
|
||||
Math.min(totalChannels, MAX_SELECTABLE_FDS),
|
||||
readFds, writeFds, exceptFds, timeout);
|
||||
}
|
||||
|
||||
private int poll(int index) throws IOException {
|
||||
// poll for helper threads
|
||||
return poll0(pollWrapper.pollArrayAddress +
|
||||
(pollArrayIndex * PollArrayWrapper.SIZE_POLLFD),
|
||||
Math.min(MAX_SELECTABLE_FDS,
|
||||
totalChannels - (index + 1) * MAX_SELECTABLE_FDS),
|
||||
readFds, writeFds, exceptFds, timeout);
|
||||
}
|
||||
|
||||
private native int poll0(long pollAddress, int numfds,
|
||||
int[] readFds, int[] writeFds, int[] exceptFds, long timeout);
|
||||
|
||||
private int processSelectedKeys(long updateCount) {
|
||||
int numKeysUpdated = 0;
|
||||
numKeysUpdated += processFDSet(updateCount, readFds,
|
||||
Net.POLLIN,
|
||||
false);
|
||||
numKeysUpdated += processFDSet(updateCount, writeFds,
|
||||
Net.POLLCONN |
|
||||
Net.POLLOUT,
|
||||
false);
|
||||
numKeysUpdated += processFDSet(updateCount, exceptFds,
|
||||
Net.POLLIN |
|
||||
Net.POLLCONN |
|
||||
Net.POLLOUT,
|
||||
true);
|
||||
return numKeysUpdated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note, clearedCount is used to determine if the readyOps have
|
||||
* been reset in this select operation. updateCount is used to
|
||||
* tell if a key has been counted as updated in this select
|
||||
* operation.
|
||||
*
|
||||
* me.updateCount <= me.clearedCount <= updateCount
|
||||
*/
|
||||
private int processFDSet(long updateCount, int[] fds, int rOps,
|
||||
boolean isExceptFds)
|
||||
{
|
||||
int numKeysUpdated = 0;
|
||||
for (int i = 1; i <= fds[0]; i++) {
|
||||
int desc = fds[i];
|
||||
if (desc == wakeupSourceFd) {
|
||||
synchronized (interruptLock) {
|
||||
interruptTriggered = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
MapEntry me = fdMap.get(desc);
|
||||
// If me is null, the key was deregistered in the previous
|
||||
// processDeregisterQueue.
|
||||
if (me == null)
|
||||
continue;
|
||||
SelectionKeyImpl sk = me.ski;
|
||||
|
||||
// The descriptor may be in the exceptfds set because there is
|
||||
// OOB data queued to the socket. If there is OOB data then it
|
||||
// is discarded and the key is not added to the selected set.
|
||||
if (isExceptFds &&
|
||||
(sk.channel() instanceof SocketChannelImpl) &&
|
||||
discardUrgentData(desc))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (selectedKeys.contains(sk)) { // Key in selected set
|
||||
if (me.clearedCount != updateCount) {
|
||||
if (sk.channel.translateAndSetReadyOps(rOps, sk) &&
|
||||
(me.updateCount != updateCount)) {
|
||||
me.updateCount = updateCount;
|
||||
numKeysUpdated++;
|
||||
}
|
||||
} else { // The readyOps have been set; now add
|
||||
if (sk.channel.translateAndUpdateReadyOps(rOps, sk) &&
|
||||
(me.updateCount != updateCount)) {
|
||||
me.updateCount = updateCount;
|
||||
numKeysUpdated++;
|
||||
}
|
||||
}
|
||||
me.clearedCount = updateCount;
|
||||
} else { // Key is not in selected set yet
|
||||
if (me.clearedCount != updateCount) {
|
||||
sk.channel.translateAndSetReadyOps(rOps, sk);
|
||||
if ((sk.nioReadyOps() & sk.nioInterestOps()) != 0) {
|
||||
selectedKeys.add(sk);
|
||||
me.updateCount = updateCount;
|
||||
numKeysUpdated++;
|
||||
}
|
||||
} else { // The readyOps have been set; now add
|
||||
sk.channel.translateAndUpdateReadyOps(rOps, sk);
|
||||
if ((sk.nioReadyOps() & sk.nioInterestOps()) != 0) {
|
||||
selectedKeys.add(sk);
|
||||
me.updateCount = updateCount;
|
||||
numKeysUpdated++;
|
||||
}
|
||||
}
|
||||
me.clearedCount = updateCount;
|
||||
}
|
||||
}
|
||||
return numKeysUpdated;
|
||||
}
|
||||
}
|
||||
|
||||
// Represents a helper thread used for select.
|
||||
private final class SelectThread extends Thread {
|
||||
private final int index; // index of this thread
|
||||
final SubSelector subSelector;
|
||||
private long lastRun = 0; // last run number
|
||||
private volatile boolean zombie;
|
||||
// Creates a new thread
|
||||
private SelectThread(int i) {
|
||||
super(null, null, "SelectorHelper", 0, false);
|
||||
this.index = i;
|
||||
this.subSelector = new SubSelector(i);
|
||||
//make sure we wait for next round of poll
|
||||
this.lastRun = startLock.runsCounter;
|
||||
}
|
||||
void makeZombie() {
|
||||
zombie = true;
|
||||
}
|
||||
boolean isZombie() {
|
||||
return zombie;
|
||||
}
|
||||
public void run() {
|
||||
while (true) { // poll loop
|
||||
// wait for the start of poll. If this thread has become
|
||||
// redundant, then exit.
|
||||
if (startLock.waitForStart(this))
|
||||
return;
|
||||
// call poll()
|
||||
try {
|
||||
subSelector.poll(index);
|
||||
} catch (IOException e) {
|
||||
// Save this exception and let other threads finish.
|
||||
finishLock.setException(e);
|
||||
}
|
||||
// notify main thread, that this thread has finished, and
|
||||
// wakeup others, if this thread is the first to finish.
|
||||
finishLock.threadFinished();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// After some channels registered/deregistered, the number of required
|
||||
// helper threads may have changed. Adjust this number.
|
||||
private void adjustThreadsCount() {
|
||||
if (threadsCount > threads.size()) {
|
||||
// More threads needed. Start more threads.
|
||||
for (int i = threads.size(); i < threadsCount; i++) {
|
||||
SelectThread newThread = new SelectThread(i);
|
||||
threads.add(newThread);
|
||||
newThread.setDaemon(true);
|
||||
newThread.start();
|
||||
}
|
||||
} else if (threadsCount < threads.size()) {
|
||||
// Some threads become redundant. Remove them from the threads List.
|
||||
for (int i = threads.size() - 1 ; i >= threadsCount; i--)
|
||||
threads.remove(i).makeZombie();
|
||||
}
|
||||
}
|
||||
|
||||
// Sets Windows wakeup socket to a signaled state.
|
||||
private void setWakeupSocket() {
|
||||
setWakeupSocket0(wakeupSinkFd);
|
||||
}
|
||||
private native void setWakeupSocket0(int wakeupSinkFd);
|
||||
|
||||
// Sets Windows wakeup socket to a non-signaled state.
|
||||
private void resetWakeupSocket() {
|
||||
synchronized (interruptLock) {
|
||||
if (interruptTriggered == false)
|
||||
return;
|
||||
resetWakeupSocket0(wakeupSourceFd);
|
||||
interruptTriggered = false;
|
||||
}
|
||||
}
|
||||
|
||||
private native void resetWakeupSocket0(int wakeupSourceFd);
|
||||
|
||||
private native boolean discardUrgentData(int fd);
|
||||
|
||||
// We increment this counter on each call to updateSelectedKeys()
|
||||
// each entry in SubSelector.fdsMap has a memorized value of
|
||||
// updateCount. When we increment numKeysUpdated we set updateCount
|
||||
// for the corresponding entry to its current value. This is used to
|
||||
// avoid counting the same key more than once - the same key can
|
||||
// appear in readfds and writefds.
|
||||
private long updateCount = 0;
|
||||
|
||||
// Update ops of the corresponding Channels. Add the ready keys to the
|
||||
// ready queue.
|
||||
private int updateSelectedKeys() {
|
||||
updateCount++;
|
||||
int numKeysUpdated = 0;
|
||||
numKeysUpdated += subSelector.processSelectedKeys(updateCount);
|
||||
for (SelectThread t: threads) {
|
||||
numKeysUpdated += t.subSelector.processSelectedKeys(updateCount);
|
||||
}
|
||||
return numKeysUpdated;
|
||||
}
|
||||
|
||||
protected void implClose() throws IOException {
|
||||
synchronized (closeLock) {
|
||||
if (channelArray != null) {
|
||||
if (pollWrapper != null) {
|
||||
// prevent further wakeup
|
||||
synchronized (interruptLock) {
|
||||
interruptTriggered = true;
|
||||
}
|
||||
wakeupPipe.sink().close();
|
||||
wakeupPipe.source().close();
|
||||
for(int i = 1; i < totalChannels; i++) { // Deregister channels
|
||||
if (i % MAX_SELECTABLE_FDS != 0) { // skip wakeupEvent
|
||||
deregister(channelArray[i]);
|
||||
SelectableChannel selch = channelArray[i].channel();
|
||||
if (!selch.isOpen() && !selch.isRegistered())
|
||||
((SelChImpl)selch).kill();
|
||||
}
|
||||
}
|
||||
pollWrapper.free();
|
||||
pollWrapper = null;
|
||||
selectedKeys = null;
|
||||
channelArray = null;
|
||||
// Make all remaining helper threads exit
|
||||
for (SelectThread t: threads)
|
||||
t.makeZombie();
|
||||
startLock.startThreads();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void implRegister(SelectionKeyImpl ski) {
|
||||
synchronized (closeLock) {
|
||||
if (pollWrapper == null)
|
||||
throw new ClosedSelectorException();
|
||||
growIfNeeded();
|
||||
channelArray[totalChannels] = ski;
|
||||
ski.setIndex(totalChannels);
|
||||
fdMap.put(ski);
|
||||
keys.add(ski);
|
||||
pollWrapper.addEntry(totalChannels, ski);
|
||||
totalChannels++;
|
||||
}
|
||||
}
|
||||
|
||||
private void growIfNeeded() {
|
||||
if (channelArray.length == totalChannels) {
|
||||
int newSize = totalChannels * 2; // Make a larger array
|
||||
SelectionKeyImpl temp[] = new SelectionKeyImpl[newSize];
|
||||
System.arraycopy(channelArray, 1, temp, 1, totalChannels - 1);
|
||||
channelArray = temp;
|
||||
pollWrapper.grow(newSize);
|
||||
}
|
||||
if (totalChannels % MAX_SELECTABLE_FDS == 0) { // more threads needed
|
||||
pollWrapper.addWakeupSocket(wakeupSourceFd, totalChannels);
|
||||
totalChannels++;
|
||||
threadsCount++;
|
||||
}
|
||||
}
|
||||
|
||||
protected void implDereg(SelectionKeyImpl ski) throws IOException{
|
||||
int i = ski.getIndex();
|
||||
assert (i >= 0);
|
||||
synchronized (closeLock) {
|
||||
if (i != totalChannels - 1) {
|
||||
// Copy end one over it
|
||||
SelectionKeyImpl endChannel = channelArray[totalChannels-1];
|
||||
channelArray[i] = endChannel;
|
||||
endChannel.setIndex(i);
|
||||
pollWrapper.replaceEntry(pollWrapper, totalChannels - 1,
|
||||
pollWrapper, i);
|
||||
}
|
||||
ski.setIndex(-1);
|
||||
}
|
||||
channelArray[totalChannels - 1] = null;
|
||||
totalChannels--;
|
||||
if ( totalChannels != 1 && totalChannels % MAX_SELECTABLE_FDS == 1) {
|
||||
totalChannels--;
|
||||
threadsCount--; // The last thread has become redundant.
|
||||
}
|
||||
fdMap.remove(ski); // Remove the key from fdMap, keys and selectedKeys
|
||||
keys.remove(ski);
|
||||
selectedKeys.remove(ski);
|
||||
deregister(ski);
|
||||
SelectableChannel selch = ski.channel();
|
||||
if (!selch.isOpen() && !selch.isRegistered())
|
||||
((SelChImpl)selch).kill();
|
||||
}
|
||||
|
||||
public void putEventOps(SelectionKeyImpl sk, int ops) {
|
||||
synchronized (closeLock) {
|
||||
if (pollWrapper == null)
|
||||
throw new ClosedSelectorException();
|
||||
// make sure this sk has not been removed yet
|
||||
int index = sk.getIndex();
|
||||
if (index == -1)
|
||||
throw new CancelledKeyException();
|
||||
pollWrapper.putEventOps(index, ops);
|
||||
}
|
||||
}
|
||||
|
||||
public Selector wakeup() {
|
||||
synchronized (interruptLock) {
|
||||
if (!interruptTriggered) {
|
||||
setWakeupSocket();
|
||||
interruptTriggered = true;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
static {
|
||||
IOUtil.load();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2002, 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 sun.nio.ch;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.spi.AbstractSelector;
|
||||
|
||||
/*
|
||||
* SelectorProvider for sun.nio.ch.WindowsSelectorImpl.
|
||||
*
|
||||
* @author Konstantin Kladko
|
||||
* @since 1.4
|
||||
*/
|
||||
|
||||
public class WindowsSelectorProvider extends SelectorProviderImpl {
|
||||
|
||||
public AbstractSelector openSelector() throws IOException {
|
||||
return new WindowsSelectorImpl(this);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue