feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
86
jdkSrc/jdk8/sun/nio/ch/AbstractPollArrayWrapper.java
Normal file
86
jdkSrc/jdk8/sun/nio/ch/AbstractPollArrayWrapper.java
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 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;
|
||||
|
||||
import sun.misc.*;
|
||||
|
||||
|
||||
/**
|
||||
* Manipulates a native array of pollfd structs.
|
||||
*
|
||||
* @author Mike McCloskey
|
||||
* @since 1.4
|
||||
*/
|
||||
|
||||
public abstract class AbstractPollArrayWrapper {
|
||||
|
||||
// Miscellaneous constants
|
||||
static final short SIZE_POLLFD = 8;
|
||||
static final short FD_OFFSET = 0;
|
||||
static final short EVENT_OFFSET = 4;
|
||||
static final short REVENT_OFFSET = 6;
|
||||
|
||||
// The poll fd array
|
||||
protected AllocatedNativeObject pollArray;
|
||||
|
||||
// Number of valid entries in the pollArray
|
||||
protected int totalChannels = 0;
|
||||
|
||||
// Base address of the native pollArray
|
||||
protected long pollArrayAddress;
|
||||
|
||||
// Access methods for fd structures
|
||||
int getEventOps(int i) {
|
||||
int offset = SIZE_POLLFD * i + EVENT_OFFSET;
|
||||
return pollArray.getShort(offset);
|
||||
}
|
||||
|
||||
int getReventOps(int i) {
|
||||
int offset = SIZE_POLLFD * i + REVENT_OFFSET;
|
||||
return pollArray.getShort(offset);
|
||||
}
|
||||
|
||||
int getDescriptor(int i) {
|
||||
int offset = SIZE_POLLFD * i + FD_OFFSET;
|
||||
return pollArray.getInt(offset);
|
||||
}
|
||||
|
||||
void putEventOps(int i, int event) {
|
||||
int offset = SIZE_POLLFD * i + EVENT_OFFSET;
|
||||
pollArray.putShort(offset, (short)event);
|
||||
}
|
||||
|
||||
void putReventOps(int i, int revent) {
|
||||
int offset = SIZE_POLLFD * i + REVENT_OFFSET;
|
||||
pollArray.putShort(offset, (short)revent);
|
||||
}
|
||||
|
||||
void putDescriptor(int i, int fd) {
|
||||
int offset = SIZE_POLLFD * i + FD_OFFSET;
|
||||
pollArray.putInt(offset, fd);
|
||||
}
|
||||
|
||||
}
|
||||
196
jdkSrc/jdk8/sun/nio/ch/AbstractPollSelectorImpl.java
Normal file
196
jdkSrc/jdk8/sun/nio/ch/AbstractPollSelectorImpl.java
Normal file
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* 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.IOException;
|
||||
import java.nio.channels.*;
|
||||
import java.nio.channels.spi.*;
|
||||
import java.util.*;
|
||||
import sun.misc.*;
|
||||
|
||||
|
||||
/**
|
||||
* An abstract selector impl.
|
||||
*/
|
||||
|
||||
abstract class AbstractPollSelectorImpl
|
||||
extends SelectorImpl
|
||||
{
|
||||
|
||||
// The poll fd array
|
||||
PollArrayWrapper pollWrapper;
|
||||
|
||||
// Initial capacity of the pollfd array
|
||||
protected final int INIT_CAP = 10;
|
||||
|
||||
// The list of SelectableChannels serviced by this Selector
|
||||
protected SelectionKeyImpl[] channelArray;
|
||||
|
||||
// In some impls the first entry of channelArray is bogus
|
||||
protected int channelOffset = 0;
|
||||
|
||||
// The number of valid channels in this Selector's poll array
|
||||
protected int totalChannels;
|
||||
|
||||
// True if this Selector has been closed
|
||||
private boolean closed = false;
|
||||
|
||||
// Lock for close and cleanup
|
||||
private Object closeLock = new Object();
|
||||
|
||||
AbstractPollSelectorImpl(SelectorProvider sp, int channels, int offset) {
|
||||
super(sp);
|
||||
this.totalChannels = channels;
|
||||
this.channelOffset = offset;
|
||||
}
|
||||
|
||||
public void putEventOps(SelectionKeyImpl sk, int ops) {
|
||||
synchronized (closeLock) {
|
||||
if (closed)
|
||||
throw new ClosedSelectorException();
|
||||
pollWrapper.putEventOps(sk.getIndex(), ops);
|
||||
}
|
||||
}
|
||||
|
||||
public Selector wakeup() {
|
||||
pollWrapper.interrupt();
|
||||
return this;
|
||||
}
|
||||
|
||||
protected abstract int doSelect(long timeout) throws IOException;
|
||||
|
||||
protected void implClose() throws IOException {
|
||||
synchronized (closeLock) {
|
||||
if (closed)
|
||||
return;
|
||||
closed = true;
|
||||
// Deregister channels
|
||||
for(int i=channelOffset; i<totalChannels; i++) {
|
||||
SelectionKeyImpl ski = channelArray[i];
|
||||
assert(ski.getIndex() != -1);
|
||||
ski.setIndex(-1);
|
||||
deregister(ski);
|
||||
SelectableChannel selch = channelArray[i].channel();
|
||||
if (!selch.isOpen() && !selch.isRegistered())
|
||||
((SelChImpl)selch).kill();
|
||||
}
|
||||
implCloseInterrupt();
|
||||
pollWrapper.free();
|
||||
pollWrapper = null;
|
||||
selectedKeys = null;
|
||||
channelArray = null;
|
||||
totalChannels = 0;
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void implCloseInterrupt() throws IOException;
|
||||
|
||||
/**
|
||||
* Copy the information in the pollfd structs into the opss
|
||||
* of the corresponding Channels. Add the ready keys to the
|
||||
* ready queue.
|
||||
*/
|
||||
protected int updateSelectedKeys() {
|
||||
int numKeysUpdated = 0;
|
||||
// Skip zeroth entry; it is for interrupts only
|
||||
for (int i=channelOffset; i<totalChannels; i++) {
|
||||
int rOps = pollWrapper.getReventOps(i);
|
||||
if (rOps != 0) {
|
||||
SelectionKeyImpl sk = channelArray[i];
|
||||
pollWrapper.putReventOps(i, 0);
|
||||
if (selectedKeys.contains(sk)) {
|
||||
if (sk.channel.translateAndSetReadyOps(rOps, sk)) {
|
||||
numKeysUpdated++;
|
||||
}
|
||||
} else {
|
||||
sk.channel.translateAndSetReadyOps(rOps, sk);
|
||||
if ((sk.nioReadyOps() & sk.nioInterestOps()) != 0) {
|
||||
selectedKeys.add(sk);
|
||||
numKeysUpdated++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return numKeysUpdated;
|
||||
}
|
||||
|
||||
protected void implRegister(SelectionKeyImpl ski) {
|
||||
synchronized (closeLock) {
|
||||
if (closed)
|
||||
throw new ClosedSelectorException();
|
||||
|
||||
// Check to see if the array is large enough
|
||||
if (channelArray.length == totalChannels) {
|
||||
// Make a larger array
|
||||
int newSize = pollWrapper.totalChannels * 2;
|
||||
SelectionKeyImpl temp[] = new SelectionKeyImpl[newSize];
|
||||
// Copy over
|
||||
for (int i=channelOffset; i<totalChannels; i++)
|
||||
temp[i] = channelArray[i];
|
||||
channelArray = temp;
|
||||
// Grow the NativeObject poll array
|
||||
pollWrapper.grow(newSize);
|
||||
}
|
||||
channelArray[totalChannels] = ski;
|
||||
ski.setIndex(totalChannels);
|
||||
pollWrapper.addEntry(ski.channel);
|
||||
totalChannels++;
|
||||
keys.add(ski);
|
||||
}
|
||||
}
|
||||
|
||||
protected void implDereg(SelectionKeyImpl ski) throws IOException {
|
||||
// Algorithm: Copy the sc from the end of the list and put it into
|
||||
// the location of the sc to be removed (since order doesn't
|
||||
// matter). Decrement the sc count. Update the index of the sc
|
||||
// that is moved.
|
||||
int i = ski.getIndex();
|
||||
assert (i >= 0);
|
||||
if (i != totalChannels - 1) {
|
||||
// Copy end one over it
|
||||
SelectionKeyImpl endChannel = channelArray[totalChannels-1];
|
||||
channelArray[i] = endChannel;
|
||||
endChannel.setIndex(i);
|
||||
pollWrapper.release(i);
|
||||
PollArrayWrapper.replaceEntry(pollWrapper, totalChannels - 1,
|
||||
pollWrapper, i);
|
||||
} else {
|
||||
pollWrapper.release(i);
|
||||
}
|
||||
// Destroy the last one
|
||||
channelArray[totalChannels-1] = null;
|
||||
totalChannels--;
|
||||
pollWrapper.totalChannels--;
|
||||
ski.setIndex(-1);
|
||||
// Remove the key from keys and selectedKeys
|
||||
keys.remove(ski);
|
||||
selectedKeys.remove(ski);
|
||||
deregister((AbstractSelectionKey)ski);
|
||||
SelectableChannel selch = ski.channel();
|
||||
if (!selch.isOpen() && !selch.isRegistered())
|
||||
((SelChImpl)selch).kill();
|
||||
}
|
||||
}
|
||||
66
jdkSrc/jdk8/sun/nio/ch/AllocatedNativeObject.java
Normal file
66
jdkSrc/jdk8/sun/nio/ch/AllocatedNativeObject.java
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, 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; // Formerly in sun.misc
|
||||
|
||||
|
||||
// ## In the fullness of time, this class will be eliminated
|
||||
|
||||
class AllocatedNativeObject // package-private
|
||||
extends NativeObject
|
||||
{
|
||||
|
||||
/**
|
||||
* Allocates a memory area of at least <tt>size</tt> bytes outside of the
|
||||
* Java heap and creates a native object for that area.
|
||||
*
|
||||
* @param size
|
||||
* Number of bytes to allocate
|
||||
*
|
||||
* @param pageAligned
|
||||
* If <tt>true</tt> then the area will be aligned on a hardware
|
||||
* page boundary
|
||||
*
|
||||
* @throws OutOfMemoryError
|
||||
* If the request cannot be satisfied
|
||||
*/
|
||||
AllocatedNativeObject(int size, boolean pageAligned) {
|
||||
super(size, pageAligned);
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees the native memory area associated with this object.
|
||||
*/
|
||||
synchronized void free() {
|
||||
if (allocationAddress != 0) {
|
||||
unsafe.freeMemory(allocationAddress);
|
||||
allocationAddress = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
341
jdkSrc/jdk8/sun/nio/ch/AsynchronousChannelGroupImpl.java
Normal file
341
jdkSrc/jdk8/sun/nio/ch/AsynchronousChannelGroupImpl.java
Normal file
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 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.nio.channels.Channel;
|
||||
import java.nio.channels.AsynchronousChannelGroup;
|
||||
import java.nio.channels.spi.AsynchronousChannelProvider;
|
||||
import java.io.IOException;
|
||||
import java.io.FileDescriptor;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.AccessController;
|
||||
import java.security.AccessControlContext;
|
||||
import sun.security.action.GetIntegerAction;
|
||||
|
||||
/**
|
||||
* Base implementation of AsynchronousChannelGroup
|
||||
*/
|
||||
|
||||
abstract class AsynchronousChannelGroupImpl
|
||||
extends AsynchronousChannelGroup implements Executor
|
||||
{
|
||||
// number of internal threads handling I/O events when using an unbounded
|
||||
// thread pool. Internal threads do not dispatch to completion handlers.
|
||||
private static final int internalThreadCount = AccessController.doPrivileged(
|
||||
new GetIntegerAction("sun.nio.ch.internalThreadPoolSize", 1));
|
||||
|
||||
// associated thread pool
|
||||
private final ThreadPool pool;
|
||||
|
||||
// number of tasks running (including internal)
|
||||
private final AtomicInteger threadCount = new AtomicInteger();
|
||||
|
||||
// associated Executor for timeouts
|
||||
private ScheduledThreadPoolExecutor timeoutExecutor;
|
||||
|
||||
// task queue for when using a fixed thread pool. In that case, thread
|
||||
// waiting on I/O events must be awokon to poll tasks from this queue.
|
||||
private final Queue<Runnable> taskQueue;
|
||||
|
||||
// group shutdown
|
||||
private final AtomicBoolean shutdown = new AtomicBoolean();
|
||||
private final Object shutdownNowLock = new Object();
|
||||
private volatile boolean terminateInitiated;
|
||||
|
||||
AsynchronousChannelGroupImpl(AsynchronousChannelProvider provider,
|
||||
ThreadPool pool)
|
||||
{
|
||||
super(provider);
|
||||
this.pool = pool;
|
||||
|
||||
if (pool.isFixedThreadPool()) {
|
||||
taskQueue = new ConcurrentLinkedQueue<Runnable>();
|
||||
} else {
|
||||
taskQueue = null; // not used
|
||||
}
|
||||
|
||||
// use default thread factory as thread should not be visible to
|
||||
// application (it doesn't execute completion handlers).
|
||||
this.timeoutExecutor = (ScheduledThreadPoolExecutor)
|
||||
Executors.newScheduledThreadPool(1, ThreadPool.defaultThreadFactory());
|
||||
this.timeoutExecutor.setRemoveOnCancelPolicy(true);
|
||||
}
|
||||
|
||||
final ExecutorService executor() {
|
||||
return pool.executor();
|
||||
}
|
||||
|
||||
final boolean isFixedThreadPool() {
|
||||
return pool.isFixedThreadPool();
|
||||
}
|
||||
|
||||
final int fixedThreadCount() {
|
||||
if (isFixedThreadPool()) {
|
||||
return pool.poolSize();
|
||||
} else {
|
||||
return pool.poolSize() + internalThreadCount;
|
||||
}
|
||||
}
|
||||
|
||||
private Runnable bindToGroup(final Runnable task) {
|
||||
final AsynchronousChannelGroupImpl thisGroup = this;
|
||||
return new Runnable() {
|
||||
public void run() {
|
||||
Invoker.bindToGroup(thisGroup);
|
||||
task.run();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void startInternalThread(final Runnable task) {
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
@Override
|
||||
public Void run() {
|
||||
// internal threads should not be visible to application so
|
||||
// cannot use user-supplied thread factory
|
||||
ThreadPool.defaultThreadFactory().newThread(task).start();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected final void startThreads(Runnable task) {
|
||||
if (!isFixedThreadPool()) {
|
||||
for (int i=0; i<internalThreadCount; i++) {
|
||||
startInternalThread(task);
|
||||
threadCount.incrementAndGet();
|
||||
}
|
||||
}
|
||||
if (pool.poolSize() > 0) {
|
||||
task = bindToGroup(task);
|
||||
try {
|
||||
for (int i=0; i<pool.poolSize(); i++) {
|
||||
pool.executor().execute(task);
|
||||
threadCount.incrementAndGet();
|
||||
}
|
||||
} catch (RejectedExecutionException x) {
|
||||
// nothing we can do
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final int threadCount() {
|
||||
return threadCount.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked by tasks as they terminate
|
||||
*/
|
||||
final int threadExit(Runnable task, boolean replaceMe) {
|
||||
if (replaceMe) {
|
||||
try {
|
||||
if (Invoker.isBoundToAnyGroup()) {
|
||||
// submit new task to replace this thread
|
||||
pool.executor().execute(bindToGroup(task));
|
||||
} else {
|
||||
// replace internal thread
|
||||
startInternalThread(task);
|
||||
}
|
||||
return threadCount.get();
|
||||
} catch (RejectedExecutionException x) {
|
||||
// unable to replace
|
||||
}
|
||||
}
|
||||
return threadCount.decrementAndGet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wakes up a thread waiting for I/O events to execute the given task.
|
||||
*/
|
||||
abstract void executeOnHandlerTask(Runnable task);
|
||||
|
||||
/**
|
||||
* For a fixed thread pool the task is queued to a thread waiting on I/O
|
||||
* events. For other thread pools we simply submit the task to the thread
|
||||
* pool.
|
||||
*/
|
||||
final void executeOnPooledThread(Runnable task) {
|
||||
if (isFixedThreadPool()) {
|
||||
executeOnHandlerTask(task);
|
||||
} else {
|
||||
pool.executor().execute(bindToGroup(task));
|
||||
}
|
||||
}
|
||||
|
||||
final void offerTask(Runnable task) {
|
||||
taskQueue.offer(task);
|
||||
}
|
||||
|
||||
final Runnable pollTask() {
|
||||
return (taskQueue == null) ? null : taskQueue.poll();
|
||||
}
|
||||
|
||||
final Future<?> schedule(Runnable task, long timeout, TimeUnit unit) {
|
||||
try {
|
||||
return timeoutExecutor.schedule(task, timeout, unit);
|
||||
} catch (RejectedExecutionException rej) {
|
||||
if (terminateInitiated) {
|
||||
// no timeout scheduled as group is terminating
|
||||
return null;
|
||||
}
|
||||
throw new AssertionError(rej);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isShutdown() {
|
||||
return shutdown.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isTerminated() {
|
||||
return pool.executor().isTerminated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if there are no channels in the group
|
||||
*/
|
||||
abstract boolean isEmpty();
|
||||
|
||||
/**
|
||||
* Attaches a foreign channel to this group.
|
||||
*/
|
||||
abstract Object attachForeignChannel(Channel channel, FileDescriptor fdo)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Detaches a foreign channel from this group.
|
||||
*/
|
||||
abstract void detachForeignChannel(Object key);
|
||||
|
||||
/**
|
||||
* Closes all channels in the group
|
||||
*/
|
||||
abstract void closeAllChannels() throws IOException;
|
||||
|
||||
/**
|
||||
* Shutdown all tasks waiting for I/O events.
|
||||
*/
|
||||
abstract void shutdownHandlerTasks();
|
||||
|
||||
private void shutdownExecutors() {
|
||||
AccessController.doPrivileged(
|
||||
new PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
pool.executor().shutdown();
|
||||
timeoutExecutor.shutdown();
|
||||
return null;
|
||||
}
|
||||
},
|
||||
null,
|
||||
new RuntimePermission("modifyThread"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void shutdown() {
|
||||
if (shutdown.getAndSet(true)) {
|
||||
// already shutdown
|
||||
return;
|
||||
}
|
||||
// if there are channels in the group then shutdown will continue
|
||||
// when the last channel is closed
|
||||
if (!isEmpty()) {
|
||||
return;
|
||||
}
|
||||
// initiate termination (acquire shutdownNowLock to ensure that other
|
||||
// threads invoking shutdownNow will block).
|
||||
synchronized (shutdownNowLock) {
|
||||
if (!terminateInitiated) {
|
||||
terminateInitiated = true;
|
||||
shutdownHandlerTasks();
|
||||
shutdownExecutors();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void shutdownNow() throws IOException {
|
||||
shutdown.set(true);
|
||||
synchronized (shutdownNowLock) {
|
||||
if (!terminateInitiated) {
|
||||
terminateInitiated = true;
|
||||
closeAllChannels();
|
||||
shutdownHandlerTasks();
|
||||
shutdownExecutors();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For use by AsynchronousFileChannel to release resources without shutting
|
||||
* down the thread pool.
|
||||
*/
|
||||
final void detachFromThreadPool() {
|
||||
if (shutdown.getAndSet(true))
|
||||
throw new AssertionError("Already shutdown");
|
||||
if (!isEmpty())
|
||||
throw new AssertionError("Group not empty");
|
||||
shutdownHandlerTasks();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean awaitTermination(long timeout, TimeUnit unit)
|
||||
throws InterruptedException
|
||||
{
|
||||
return pool.executor().awaitTermination(timeout, unit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the given command on one of the channel group's pooled threads.
|
||||
*/
|
||||
@Override
|
||||
public final void execute(Runnable task) {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
// when a security manager is installed then the user's task
|
||||
// must be run with the current calling context
|
||||
final AccessControlContext acc = AccessController.getContext();
|
||||
final Runnable delegate = task;
|
||||
task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
@Override
|
||||
public Void run() {
|
||||
delegate.run();
|
||||
return null;
|
||||
}
|
||||
}, acc);
|
||||
}
|
||||
};
|
||||
}
|
||||
executeOnPooledThread(task);
|
||||
}
|
||||
}
|
||||
253
jdkSrc/jdk8/sun/nio/ch/AsynchronousFileChannelImpl.java
Normal file
253
jdkSrc/jdk8/sun/nio/ch/AsynchronousFileChannelImpl.java
Normal file
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* 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.ByteBuffer;
|
||||
import java.nio.channels.*;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.locks.*;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Base implementation of AsynchronousFileChannel.
|
||||
*/
|
||||
|
||||
abstract class AsynchronousFileChannelImpl
|
||||
extends AsynchronousFileChannel
|
||||
{
|
||||
// close support
|
||||
protected final ReadWriteLock closeLock = new ReentrantReadWriteLock();
|
||||
protected volatile boolean closed;
|
||||
|
||||
// file descriptor
|
||||
protected final FileDescriptor fdObj;
|
||||
|
||||
// indicates if open for reading/writing
|
||||
protected final boolean reading;
|
||||
protected final boolean writing;
|
||||
|
||||
// associated Executor
|
||||
protected final ExecutorService executor;
|
||||
|
||||
protected AsynchronousFileChannelImpl(FileDescriptor fdObj,
|
||||
boolean reading,
|
||||
boolean writing,
|
||||
ExecutorService executor)
|
||||
{
|
||||
this.fdObj = fdObj;
|
||||
this.reading = reading;
|
||||
this.writing = writing;
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
final ExecutorService executor() {
|
||||
return executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isOpen() {
|
||||
return !closed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the beginning of an I/O operation.
|
||||
*
|
||||
* @throws ClosedChannelException If channel is closed
|
||||
*/
|
||||
protected final void begin() throws IOException {
|
||||
closeLock.readLock().lock();
|
||||
if (closed)
|
||||
throw new ClosedChannelException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the end of an I/O operation.
|
||||
*/
|
||||
protected final void end() {
|
||||
closeLock.readLock().unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks end of I/O operation
|
||||
*/
|
||||
protected final void end(boolean completed) throws IOException {
|
||||
end();
|
||||
if (!completed && !isOpen())
|
||||
throw new AsynchronousCloseException();
|
||||
}
|
||||
|
||||
// -- file locking --
|
||||
|
||||
abstract <A> Future<FileLock> implLock(long position,
|
||||
long size,
|
||||
boolean shared,
|
||||
A attachment,
|
||||
CompletionHandler<FileLock,? super A> handler);
|
||||
|
||||
@Override
|
||||
public final Future<FileLock> lock(long position,
|
||||
long size,
|
||||
boolean shared)
|
||||
|
||||
{
|
||||
return implLock(position, size, shared, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <A> void lock(long position,
|
||||
long size,
|
||||
boolean shared,
|
||||
A attachment,
|
||||
CompletionHandler<FileLock,? super A> handler)
|
||||
{
|
||||
if (handler == null)
|
||||
throw new NullPointerException("'handler' is null");
|
||||
implLock(position, size, shared, attachment, handler);
|
||||
}
|
||||
|
||||
private volatile FileLockTable fileLockTable;
|
||||
|
||||
final void ensureFileLockTableInitialized() throws IOException {
|
||||
if (fileLockTable == null) {
|
||||
synchronized (this) {
|
||||
if (fileLockTable == null) {
|
||||
fileLockTable = FileLockTable.newSharedFileLockTable(this, fdObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final void invalidateAllLocks() throws IOException {
|
||||
if (fileLockTable != null) {
|
||||
for (FileLock fl: fileLockTable.removeAll()) {
|
||||
synchronized (fl) {
|
||||
if (fl.isValid()) {
|
||||
FileLockImpl fli = (FileLockImpl)fl;
|
||||
implRelease(fli);
|
||||
fli.invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds region to lock table
|
||||
*/
|
||||
protected final FileLockImpl addToFileLockTable(long position, long size, boolean shared) {
|
||||
final FileLockImpl fli;
|
||||
try {
|
||||
// like begin() but returns null instead of exception
|
||||
closeLock.readLock().lock();
|
||||
if (closed)
|
||||
return null;
|
||||
|
||||
try {
|
||||
ensureFileLockTableInitialized();
|
||||
} catch (IOException x) {
|
||||
// should not happen
|
||||
throw new AssertionError(x);
|
||||
}
|
||||
fli = new FileLockImpl(this, position, size, shared);
|
||||
// may throw OverlappedFileLockException
|
||||
fileLockTable.add(fli);
|
||||
} finally {
|
||||
end();
|
||||
}
|
||||
return fli;
|
||||
}
|
||||
|
||||
protected final void removeFromFileLockTable(FileLockImpl fli) {
|
||||
fileLockTable.remove(fli);
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the given file lock.
|
||||
*/
|
||||
protected abstract void implRelease(FileLockImpl fli) throws IOException;
|
||||
|
||||
/**
|
||||
* Invoked by FileLockImpl to release the given file lock and remove it
|
||||
* from the lock table.
|
||||
*/
|
||||
final void release(FileLockImpl fli) throws IOException {
|
||||
try {
|
||||
begin();
|
||||
implRelease(fli);
|
||||
removeFromFileLockTable(fli);
|
||||
} finally {
|
||||
end();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -- reading and writing --
|
||||
|
||||
abstract <A> Future<Integer> implRead(ByteBuffer dst,
|
||||
long position,
|
||||
A attachment,
|
||||
CompletionHandler<Integer,? super A> handler);
|
||||
|
||||
@Override
|
||||
public final Future<Integer> read(ByteBuffer dst, long position) {
|
||||
return implRead(dst, position, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <A> void read(ByteBuffer dst,
|
||||
long position,
|
||||
A attachment,
|
||||
CompletionHandler<Integer,? super A> handler)
|
||||
{
|
||||
if (handler == null)
|
||||
throw new NullPointerException("'handler' is null");
|
||||
implRead(dst, position, attachment, handler);
|
||||
}
|
||||
|
||||
abstract <A> Future<Integer> implWrite(ByteBuffer src,
|
||||
long position,
|
||||
A attachment,
|
||||
CompletionHandler<Integer,? super A> handler);
|
||||
|
||||
|
||||
@Override
|
||||
public final Future<Integer> write(ByteBuffer src, long position) {
|
||||
return implWrite(src, position, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <A> void write(ByteBuffer src,
|
||||
long position,
|
||||
A attachment,
|
||||
CompletionHandler<Integer,? super A> handler)
|
||||
{
|
||||
if (handler == null)
|
||||
throw new NullPointerException("'handler' is null");
|
||||
implWrite(src, position, attachment, handler);
|
||||
}
|
||||
}
|
||||
262
jdkSrc/jdk8/sun/nio/ch/AsynchronousServerSocketChannelImpl.java
Normal file
262
jdkSrc/jdk8/sun/nio/ch/AsynchronousServerSocketChannelImpl.java
Normal file
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2018, 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.SocketAddress;
|
||||
import java.net.SocketOption;
|
||||
import java.net.StandardSocketOptions;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import sun.net.NetHooks;
|
||||
import sun.net.ExtendedOptionsHelper;
|
||||
|
||||
/**
|
||||
* Base implementation of AsynchronousServerSocketChannel.
|
||||
*/
|
||||
|
||||
abstract class AsynchronousServerSocketChannelImpl
|
||||
extends AsynchronousServerSocketChannel
|
||||
implements Cancellable, Groupable
|
||||
{
|
||||
protected final FileDescriptor fd;
|
||||
|
||||
// the local address to which the channel's socket is bound
|
||||
protected volatile InetSocketAddress localAddress = null;
|
||||
|
||||
// need this lock to set local address
|
||||
private final Object stateLock = new Object();
|
||||
|
||||
// close support
|
||||
private ReadWriteLock closeLock = new ReentrantReadWriteLock();
|
||||
private volatile boolean open = true;
|
||||
|
||||
// set true when accept operation is cancelled
|
||||
private volatile boolean acceptKilled;
|
||||
|
||||
// set true when exclusive binding is on and SO_REUSEADDR is emulated
|
||||
private boolean isReuseAddress;
|
||||
|
||||
AsynchronousServerSocketChannelImpl(AsynchronousChannelGroupImpl group) {
|
||||
super(group.provider());
|
||||
this.fd = Net.serverSocket(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isOpen() {
|
||||
return open;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks beginning of access to file descriptor/handle
|
||||
*/
|
||||
final void begin() throws IOException {
|
||||
closeLock.readLock().lock();
|
||||
if (!isOpen())
|
||||
throw new ClosedChannelException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks end of access to file descriptor/handle
|
||||
*/
|
||||
final void end() {
|
||||
closeLock.readLock().unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked to close file descriptor/handle.
|
||||
*/
|
||||
abstract void implClose() throws IOException;
|
||||
|
||||
@Override
|
||||
public final void close() throws IOException {
|
||||
// synchronize with any threads using file descriptor/handle
|
||||
closeLock.writeLock().lock();
|
||||
try {
|
||||
if (!open)
|
||||
return; // already closed
|
||||
open = false;
|
||||
} finally {
|
||||
closeLock.writeLock().unlock();
|
||||
}
|
||||
implClose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked by accept to accept connection
|
||||
*/
|
||||
abstract Future<AsynchronousSocketChannel>
|
||||
implAccept(Object attachment,
|
||||
CompletionHandler<AsynchronousSocketChannel,Object> handler);
|
||||
|
||||
|
||||
@Override
|
||||
public final Future<AsynchronousSocketChannel> accept() {
|
||||
return implAccept(null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public final <A> void accept(A attachment,
|
||||
CompletionHandler<AsynchronousSocketChannel,? super A> handler)
|
||||
{
|
||||
if (handler == null)
|
||||
throw new NullPointerException("'handler' is null");
|
||||
implAccept(attachment, (CompletionHandler<AsynchronousSocketChannel,Object>)handler);
|
||||
}
|
||||
|
||||
final boolean isAcceptKilled() {
|
||||
return acceptKilled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onCancel(PendingFuture<?,?> task) {
|
||||
acceptKilled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final AsynchronousServerSocketChannel bind(SocketAddress local, int backlog)
|
||||
throws IOException
|
||||
{
|
||||
InetSocketAddress isa = (local == null) ? new InetSocketAddress(0) :
|
||||
Net.checkAddress(local);
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null)
|
||||
sm.checkListen(isa.getPort());
|
||||
|
||||
try {
|
||||
begin();
|
||||
synchronized (stateLock) {
|
||||
if (localAddress != null)
|
||||
throw new AlreadyBoundException();
|
||||
NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
|
||||
Net.bind(fd, isa.getAddress(), isa.getPort());
|
||||
Net.listen(fd, backlog < 1 ? 50 : backlog);
|
||||
localAddress = Net.localAddress(fd);
|
||||
}
|
||||
} finally {
|
||||
end();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final SocketAddress getLocalAddress() throws IOException {
|
||||
if (!isOpen())
|
||||
throw new ClosedChannelException();
|
||||
return Net.getRevealedLocalAddress(localAddress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> AsynchronousServerSocketChannel setOption(SocketOption<T> name,
|
||||
T value)
|
||||
throws IOException
|
||||
{
|
||||
if (name == null)
|
||||
throw new NullPointerException();
|
||||
if (!supportedOptions().contains(name))
|
||||
throw new UnsupportedOperationException("'" + name + "' not supported");
|
||||
|
||||
try {
|
||||
begin();
|
||||
if (name == StandardSocketOptions.SO_REUSEADDR &&
|
||||
Net.useExclusiveBind())
|
||||
{
|
||||
// SO_REUSEADDR emulated when using exclusive bind
|
||||
isReuseAddress = (Boolean)value;
|
||||
} else {
|
||||
Net.setSocketOption(fd, Net.UNSPEC, name, value);
|
||||
}
|
||||
return this;
|
||||
} finally {
|
||||
end();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public final <T> T getOption(SocketOption<T> name) throws IOException {
|
||||
if (name == null)
|
||||
throw new NullPointerException();
|
||||
if (!supportedOptions().contains(name))
|
||||
throw new UnsupportedOperationException("'" + name + "' not supported");
|
||||
|
||||
try {
|
||||
begin();
|
||||
if (name == StandardSocketOptions.SO_REUSEADDR &&
|
||||
Net.useExclusiveBind())
|
||||
{
|
||||
// SO_REUSEADDR emulated when using exclusive bind
|
||||
return (T)Boolean.valueOf(isReuseAddress);
|
||||
}
|
||||
return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
|
||||
} finally {
|
||||
end();
|
||||
}
|
||||
}
|
||||
|
||||
private static class DefaultOptionsHolder {
|
||||
static final Set<SocketOption<?>> defaultOptions = defaultOptions();
|
||||
|
||||
private static Set<SocketOption<?>> defaultOptions() {
|
||||
HashSet<SocketOption<?>> set = new HashSet<SocketOption<?>>(2);
|
||||
set.add(StandardSocketOptions.SO_RCVBUF);
|
||||
set.add(StandardSocketOptions.SO_REUSEADDR);
|
||||
set.addAll(ExtendedOptionsHelper.keepAliveOptions());
|
||||
return Collections.unmodifiableSet(set);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Set<SocketOption<?>> supportedOptions() {
|
||||
return DefaultOptionsHolder.defaultOptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(this.getClass().getName());
|
||||
sb.append('[');
|
||||
if (!isOpen())
|
||||
sb.append("closed");
|
||||
else {
|
||||
if (localAddress == null) {
|
||||
sb.append("unbound");
|
||||
} else {
|
||||
sb.append(Net.getRevealedLocalAddressAsString(localAddress));
|
||||
}
|
||||
}
|
||||
sb.append(']');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
607
jdkSrc/jdk8/sun/nio/ch/AsynchronousSocketChannelImpl.java
Normal file
607
jdkSrc/jdk8/sun/nio/ch/AsynchronousSocketChannelImpl.java
Normal file
@@ -0,0 +1,607 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2018, 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.ByteBuffer;
|
||||
import java.nio.channels.*;
|
||||
import java.net.SocketOption;
|
||||
import java.net.StandardSocketOptions;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.io.IOException;
|
||||
import java.io.FileDescriptor;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.locks.*;
|
||||
import sun.net.NetHooks;
|
||||
import sun.net.ExtendedOptionsImpl;
|
||||
import sun.net.ExtendedOptionsHelper;
|
||||
|
||||
/**
|
||||
* Base implementation of AsynchronousSocketChannel
|
||||
*/
|
||||
|
||||
abstract class AsynchronousSocketChannelImpl
|
||||
extends AsynchronousSocketChannel
|
||||
implements Cancellable, Groupable
|
||||
{
|
||||
protected final FileDescriptor fd;
|
||||
|
||||
// protects state, localAddress, and remoteAddress
|
||||
protected final Object stateLock = new Object();
|
||||
|
||||
protected volatile InetSocketAddress localAddress = null;
|
||||
protected volatile InetSocketAddress remoteAddress = null;
|
||||
|
||||
// State, increases monotonically
|
||||
static final int ST_UNINITIALIZED = -1;
|
||||
static final int ST_UNCONNECTED = 0;
|
||||
static final int ST_PENDING = 1;
|
||||
static final int ST_CONNECTED = 2;
|
||||
protected volatile int state = ST_UNINITIALIZED;
|
||||
|
||||
// reading state
|
||||
private final Object readLock = new Object();
|
||||
private boolean reading;
|
||||
private boolean readShutdown;
|
||||
private boolean readKilled; // further reading disallowed due to timeout
|
||||
|
||||
// writing state
|
||||
private final Object writeLock = new Object();
|
||||
private boolean writing;
|
||||
private boolean writeShutdown;
|
||||
private boolean writeKilled; // further writing disallowed due to timeout
|
||||
|
||||
// close support
|
||||
private final ReadWriteLock closeLock = new ReentrantReadWriteLock();
|
||||
private volatile boolean open = true;
|
||||
|
||||
// set true when exclusive binding is on and SO_REUSEADDR is emulated
|
||||
private boolean isReuseAddress;
|
||||
|
||||
AsynchronousSocketChannelImpl(AsynchronousChannelGroupImpl group)
|
||||
throws IOException
|
||||
{
|
||||
super(group.provider());
|
||||
this.fd = Net.socket(true);
|
||||
this.state = ST_UNCONNECTED;
|
||||
}
|
||||
|
||||
// Constructor for sockets obtained from AsynchronousServerSocketChannelImpl
|
||||
AsynchronousSocketChannelImpl(AsynchronousChannelGroupImpl group,
|
||||
FileDescriptor fd,
|
||||
InetSocketAddress remote)
|
||||
throws IOException
|
||||
{
|
||||
super(group.provider());
|
||||
this.fd = fd;
|
||||
this.state = ST_CONNECTED;
|
||||
this.localAddress = Net.localAddress(fd);
|
||||
this.remoteAddress = remote;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isOpen() {
|
||||
return open;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks beginning of access to file descriptor/handle
|
||||
*/
|
||||
final void begin() throws IOException {
|
||||
closeLock.readLock().lock();
|
||||
if (!isOpen())
|
||||
throw new ClosedChannelException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks end of access to file descriptor/handle
|
||||
*/
|
||||
final void end() {
|
||||
closeLock.readLock().unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked to close socket and release other resources.
|
||||
*/
|
||||
abstract void implClose() throws IOException;
|
||||
|
||||
@Override
|
||||
public final void close() throws IOException {
|
||||
// synchronize with any threads initiating asynchronous operations
|
||||
closeLock.writeLock().lock();
|
||||
try {
|
||||
if (!open)
|
||||
return; // already closed
|
||||
open = false;
|
||||
} finally {
|
||||
closeLock.writeLock().unlock();
|
||||
}
|
||||
implClose();
|
||||
}
|
||||
|
||||
final void enableReading(boolean killed) {
|
||||
synchronized (readLock) {
|
||||
reading = false;
|
||||
if (killed)
|
||||
readKilled = true;
|
||||
}
|
||||
}
|
||||
|
||||
final void enableReading() {
|
||||
enableReading(false);
|
||||
}
|
||||
|
||||
final void enableWriting(boolean killed) {
|
||||
synchronized (writeLock) {
|
||||
writing = false;
|
||||
if (killed)
|
||||
writeKilled = true;
|
||||
}
|
||||
}
|
||||
|
||||
final void enableWriting() {
|
||||
enableWriting(false);
|
||||
}
|
||||
|
||||
final void killReading() {
|
||||
synchronized (readLock) {
|
||||
readKilled = true;
|
||||
}
|
||||
}
|
||||
|
||||
final void killWriting() {
|
||||
synchronized (writeLock) {
|
||||
writeKilled = true;
|
||||
}
|
||||
}
|
||||
|
||||
final void killConnect() {
|
||||
// when a connect is cancelled then the connection may have been
|
||||
// established so prevent reading or writing.
|
||||
killReading();
|
||||
killWriting();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked by connect to initiate the connect operation.
|
||||
*/
|
||||
abstract <A> Future<Void> implConnect(SocketAddress remote,
|
||||
A attachment,
|
||||
CompletionHandler<Void,? super A> handler);
|
||||
|
||||
@Override
|
||||
public final Future<Void> connect(SocketAddress remote) {
|
||||
return implConnect(remote, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <A> void connect(SocketAddress remote,
|
||||
A attachment,
|
||||
CompletionHandler<Void,? super A> handler)
|
||||
{
|
||||
if (handler == null)
|
||||
throw new NullPointerException("'handler' is null");
|
||||
implConnect(remote, attachment, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked by read to initiate the I/O operation.
|
||||
*/
|
||||
abstract <V extends Number,A> Future<V> implRead(boolean isScatteringRead,
|
||||
ByteBuffer dst,
|
||||
ByteBuffer[] dsts,
|
||||
long timeout,
|
||||
TimeUnit unit,
|
||||
A attachment,
|
||||
CompletionHandler<V,? super A> handler);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <V extends Number,A> Future<V> read(boolean isScatteringRead,
|
||||
ByteBuffer dst,
|
||||
ByteBuffer[] dsts,
|
||||
long timeout,
|
||||
TimeUnit unit,
|
||||
A att,
|
||||
CompletionHandler<V,? super A> handler)
|
||||
{
|
||||
if (!isOpen()) {
|
||||
Throwable e = new ClosedChannelException();
|
||||
if (handler == null)
|
||||
return CompletedFuture.withFailure(e);
|
||||
Invoker.invoke(this, handler, att, null, e);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (remoteAddress == null)
|
||||
throw new NotYetConnectedException();
|
||||
|
||||
boolean hasSpaceToRead = isScatteringRead || dst.hasRemaining();
|
||||
boolean shutdown = false;
|
||||
|
||||
// check and update state
|
||||
synchronized (readLock) {
|
||||
if (readKilled)
|
||||
throw new IllegalStateException("Reading not allowed due to timeout or cancellation");
|
||||
if (reading)
|
||||
throw new ReadPendingException();
|
||||
if (readShutdown) {
|
||||
shutdown = true;
|
||||
} else {
|
||||
if (hasSpaceToRead) {
|
||||
reading = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// immediately complete with -1 if shutdown for read
|
||||
// immediately complete with 0 if no space remaining
|
||||
if (shutdown || !hasSpaceToRead) {
|
||||
Number result;
|
||||
if (isScatteringRead) {
|
||||
result = (shutdown) ? Long.valueOf(-1L) : Long.valueOf(0L);
|
||||
} else {
|
||||
result = (shutdown) ? -1 : 0;
|
||||
}
|
||||
if (handler == null)
|
||||
return CompletedFuture.withResult((V)result);
|
||||
Invoker.invoke(this, handler, att, (V)result, null);
|
||||
return null;
|
||||
}
|
||||
|
||||
return implRead(isScatteringRead, dst, dsts, timeout, unit, att, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Future<Integer> read(ByteBuffer dst) {
|
||||
if (dst.isReadOnly())
|
||||
throw new IllegalArgumentException("Read-only buffer");
|
||||
return read(false, dst, null, 0L, TimeUnit.MILLISECONDS, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <A> void read(ByteBuffer dst,
|
||||
long timeout,
|
||||
TimeUnit unit,
|
||||
A attachment,
|
||||
CompletionHandler<Integer,? super A> handler)
|
||||
{
|
||||
if (handler == null)
|
||||
throw new NullPointerException("'handler' is null");
|
||||
if (dst.isReadOnly())
|
||||
throw new IllegalArgumentException("Read-only buffer");
|
||||
read(false, dst, null, timeout, unit, attachment, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <A> void read(ByteBuffer[] dsts,
|
||||
int offset,
|
||||
int length,
|
||||
long timeout,
|
||||
TimeUnit unit,
|
||||
A attachment,
|
||||
CompletionHandler<Long,? super A> handler)
|
||||
{
|
||||
if (handler == null)
|
||||
throw new NullPointerException("'handler' is null");
|
||||
if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
|
||||
throw new IndexOutOfBoundsException();
|
||||
ByteBuffer[] bufs = Util.subsequence(dsts, offset, length);
|
||||
for (int i=0; i<bufs.length; i++) {
|
||||
if (bufs[i].isReadOnly())
|
||||
throw new IllegalArgumentException("Read-only buffer");
|
||||
}
|
||||
read(true, null, bufs, timeout, unit, attachment, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked by write to initiate the I/O operation.
|
||||
*/
|
||||
abstract <V extends Number,A> Future<V> implWrite(boolean isGatheringWrite,
|
||||
ByteBuffer src,
|
||||
ByteBuffer[] srcs,
|
||||
long timeout,
|
||||
TimeUnit unit,
|
||||
A attachment,
|
||||
CompletionHandler<V,? super A> handler);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <V extends Number,A> Future<V> write(boolean isGatheringWrite,
|
||||
ByteBuffer src,
|
||||
ByteBuffer[] srcs,
|
||||
long timeout,
|
||||
TimeUnit unit,
|
||||
A att,
|
||||
CompletionHandler<V,? super A> handler)
|
||||
{
|
||||
boolean hasDataToWrite = isGatheringWrite || src.hasRemaining();
|
||||
|
||||
boolean closed = false;
|
||||
if (isOpen()) {
|
||||
if (remoteAddress == null)
|
||||
throw new NotYetConnectedException();
|
||||
// check and update state
|
||||
synchronized (writeLock) {
|
||||
if (writeKilled)
|
||||
throw new IllegalStateException("Writing not allowed due to timeout or cancellation");
|
||||
if (writing)
|
||||
throw new WritePendingException();
|
||||
if (writeShutdown) {
|
||||
closed = true;
|
||||
} else {
|
||||
if (hasDataToWrite)
|
||||
writing = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
closed = true;
|
||||
}
|
||||
|
||||
// channel is closed or shutdown for write
|
||||
if (closed) {
|
||||
Throwable e = new ClosedChannelException();
|
||||
if (handler == null)
|
||||
return CompletedFuture.withFailure(e);
|
||||
Invoker.invoke(this, handler, att, null, e);
|
||||
return null;
|
||||
}
|
||||
|
||||
// nothing to write so complete immediately
|
||||
if (!hasDataToWrite) {
|
||||
Number result = (isGatheringWrite) ? (Number)0L : (Number)0;
|
||||
if (handler == null)
|
||||
return CompletedFuture.withResult((V)result);
|
||||
Invoker.invoke(this, handler, att, (V)result, null);
|
||||
return null;
|
||||
}
|
||||
|
||||
return implWrite(isGatheringWrite, src, srcs, timeout, unit, att, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Future<Integer> write(ByteBuffer src) {
|
||||
return write(false, src, null, 0L, TimeUnit.MILLISECONDS, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <A> void write(ByteBuffer src,
|
||||
long timeout,
|
||||
TimeUnit unit,
|
||||
A attachment,
|
||||
CompletionHandler<Integer,? super A> handler)
|
||||
{
|
||||
if (handler == null)
|
||||
throw new NullPointerException("'handler' is null");
|
||||
write(false, src, null, timeout, unit, attachment, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <A> void write(ByteBuffer[] srcs,
|
||||
int offset,
|
||||
int length,
|
||||
long timeout,
|
||||
TimeUnit unit,
|
||||
A attachment,
|
||||
CompletionHandler<Long,? super A> handler)
|
||||
{
|
||||
if (handler == null)
|
||||
throw new NullPointerException("'handler' is null");
|
||||
if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
|
||||
throw new IndexOutOfBoundsException();
|
||||
srcs = Util.subsequence(srcs, offset, length);
|
||||
write(true, null, srcs, timeout, unit, attachment, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final AsynchronousSocketChannel bind(SocketAddress local)
|
||||
throws IOException
|
||||
{
|
||||
try {
|
||||
begin();
|
||||
synchronized (stateLock) {
|
||||
if (state == ST_PENDING)
|
||||
throw new ConnectionPendingException();
|
||||
if (localAddress != null)
|
||||
throw new AlreadyBoundException();
|
||||
InetSocketAddress isa = (local == null) ?
|
||||
new InetSocketAddress(0) : Net.checkAddress(local);
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkListen(isa.getPort());
|
||||
}
|
||||
NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
|
||||
Net.bind(fd, isa.getAddress(), isa.getPort());
|
||||
localAddress = Net.localAddress(fd);
|
||||
}
|
||||
} finally {
|
||||
end();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final SocketAddress getLocalAddress() throws IOException {
|
||||
if (!isOpen())
|
||||
throw new ClosedChannelException();
|
||||
return Net.getRevealedLocalAddress(localAddress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> AsynchronousSocketChannel setOption(SocketOption<T> name, T value)
|
||||
throws IOException
|
||||
{
|
||||
if (name == null)
|
||||
throw new NullPointerException();
|
||||
if (!supportedOptions().contains(name))
|
||||
throw new UnsupportedOperationException("'" + name + "' not supported");
|
||||
|
||||
try {
|
||||
begin();
|
||||
if (writeShutdown)
|
||||
throw new IOException("Connection has been shutdown for writing");
|
||||
if (name == StandardSocketOptions.SO_REUSEADDR &&
|
||||
Net.useExclusiveBind())
|
||||
{
|
||||
// SO_REUSEADDR emulated when using exclusive bind
|
||||
isReuseAddress = (Boolean)value;
|
||||
} else {
|
||||
Net.setSocketOption(fd, Net.UNSPEC, name, value);
|
||||
}
|
||||
return this;
|
||||
} finally {
|
||||
end();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public final <T> T getOption(SocketOption<T> name) throws IOException {
|
||||
if (name == null)
|
||||
throw new NullPointerException();
|
||||
if (!supportedOptions().contains(name))
|
||||
throw new UnsupportedOperationException("'" + name + "' not supported");
|
||||
|
||||
try {
|
||||
begin();
|
||||
if (name == StandardSocketOptions.SO_REUSEADDR &&
|
||||
Net.useExclusiveBind())
|
||||
{
|
||||
// SO_REUSEADDR emulated when using exclusive bind
|
||||
return (T)Boolean.valueOf(isReuseAddress);
|
||||
}
|
||||
return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
|
||||
} finally {
|
||||
end();
|
||||
}
|
||||
}
|
||||
|
||||
private static class DefaultOptionsHolder {
|
||||
static final Set<SocketOption<?>> defaultOptions = defaultOptions();
|
||||
|
||||
private static Set<SocketOption<?>> defaultOptions() {
|
||||
HashSet<SocketOption<?>> set = new HashSet<SocketOption<?>>(5);
|
||||
set.add(StandardSocketOptions.SO_SNDBUF);
|
||||
set.add(StandardSocketOptions.SO_RCVBUF);
|
||||
set.add(StandardSocketOptions.SO_KEEPALIVE);
|
||||
set.add(StandardSocketOptions.SO_REUSEADDR);
|
||||
set.add(StandardSocketOptions.TCP_NODELAY);
|
||||
if (ExtendedOptionsImpl.flowSupported()) {
|
||||
set.add(jdk.net.ExtendedSocketOptions.SO_FLOW_SLA);
|
||||
}
|
||||
set.addAll(ExtendedOptionsHelper.keepAliveOptions());
|
||||
return Collections.unmodifiableSet(set);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Set<SocketOption<?>> supportedOptions() {
|
||||
return DefaultOptionsHolder.defaultOptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final SocketAddress getRemoteAddress() throws IOException {
|
||||
if (!isOpen())
|
||||
throw new ClosedChannelException();
|
||||
return remoteAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final AsynchronousSocketChannel shutdownInput() throws IOException {
|
||||
try {
|
||||
begin();
|
||||
if (remoteAddress == null)
|
||||
throw new NotYetConnectedException();
|
||||
synchronized (readLock) {
|
||||
if (!readShutdown) {
|
||||
Net.shutdown(fd, Net.SHUT_RD);
|
||||
readShutdown = true;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
end();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final AsynchronousSocketChannel shutdownOutput() throws IOException {
|
||||
try {
|
||||
begin();
|
||||
if (remoteAddress == null)
|
||||
throw new NotYetConnectedException();
|
||||
synchronized (writeLock) {
|
||||
if (!writeShutdown) {
|
||||
Net.shutdown(fd, Net.SHUT_WR);
|
||||
writeShutdown = true;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
end();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(this.getClass().getName());
|
||||
sb.append('[');
|
||||
synchronized (stateLock) {
|
||||
if (!isOpen()) {
|
||||
sb.append("closed");
|
||||
} else {
|
||||
switch (state) {
|
||||
case ST_UNCONNECTED:
|
||||
sb.append("unconnected");
|
||||
break;
|
||||
case ST_PENDING:
|
||||
sb.append("connection-pending");
|
||||
break;
|
||||
case ST_CONNECTED:
|
||||
sb.append("connected");
|
||||
if (readShutdown)
|
||||
sb.append(" ishut");
|
||||
if (writeShutdown)
|
||||
sb.append(" oshut");
|
||||
break;
|
||||
}
|
||||
if (localAddress != null) {
|
||||
sb.append(" local=");
|
||||
sb.append(
|
||||
Net.getRevealedLocalAddressAsString(localAddress));
|
||||
}
|
||||
if (remoteAddress != null) {
|
||||
sb.append(" remote=");
|
||||
sb.append(remoteAddress.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
sb.append(']');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
39
jdkSrc/jdk8/sun/nio/ch/Cancellable.java
Normal file
39
jdkSrc/jdk8/sun/nio/ch/Cancellable.java
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Implemented by asynchronous channels that require notification when an I/O
|
||||
* operation is cancelled.
|
||||
*/
|
||||
|
||||
interface Cancellable {
|
||||
/**
|
||||
* Invoked to notify channel that cancel has been invoked while holding
|
||||
* the Future's lock.
|
||||
*/
|
||||
void onCancel(PendingFuture<?,?> task);
|
||||
}
|
||||
126
jdkSrc/jdk8/sun/nio/ch/ChannelInputStream.java
Normal file
126
jdkSrc/jdk8/sun/nio/ch/ChannelInputStream.java
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* 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.io.*;
|
||||
import java.nio.*;
|
||||
import java.nio.channels.*;
|
||||
import java.nio.channels.spi.*;
|
||||
|
||||
|
||||
/**
|
||||
* This class is defined here rather than in java.nio.channels.Channels
|
||||
* so that code can be shared with SocketAdaptor.
|
||||
*
|
||||
* @author Mike McCloskey
|
||||
* @author Mark Reinhold
|
||||
* @since 1.4
|
||||
*/
|
||||
|
||||
public class ChannelInputStream
|
||||
extends InputStream
|
||||
{
|
||||
|
||||
public static int read(ReadableByteChannel ch, ByteBuffer bb,
|
||||
boolean block)
|
||||
throws IOException
|
||||
{
|
||||
if (ch instanceof SelectableChannel) {
|
||||
SelectableChannel sc = (SelectableChannel)ch;
|
||||
synchronized (sc.blockingLock()) {
|
||||
boolean bm = sc.isBlocking();
|
||||
if (!bm)
|
||||
throw new IllegalBlockingModeException();
|
||||
if (bm != block)
|
||||
sc.configureBlocking(block);
|
||||
int n = ch.read(bb);
|
||||
if (bm != block)
|
||||
sc.configureBlocking(bm);
|
||||
return n;
|
||||
}
|
||||
} else {
|
||||
return ch.read(bb);
|
||||
}
|
||||
}
|
||||
|
||||
protected final ReadableByteChannel ch;
|
||||
private ByteBuffer bb = null;
|
||||
private byte[] bs = null; // Invoker's previous array
|
||||
private byte[] b1 = null;
|
||||
|
||||
public ChannelInputStream(ReadableByteChannel ch) {
|
||||
this.ch = ch;
|
||||
}
|
||||
|
||||
public synchronized int read() throws IOException {
|
||||
if (b1 == null)
|
||||
b1 = new byte[1];
|
||||
int n = this.read(b1);
|
||||
if (n == 1)
|
||||
return b1[0] & 0xff;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public synchronized int read(byte[] bs, int off, int len)
|
||||
throws IOException
|
||||
{
|
||||
if ((off < 0) || (off > bs.length) || (len < 0) ||
|
||||
((off + len) > bs.length) || ((off + len) < 0)) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
} else if (len == 0)
|
||||
return 0;
|
||||
|
||||
ByteBuffer bb = ((this.bs == bs)
|
||||
? this.bb
|
||||
: ByteBuffer.wrap(bs));
|
||||
bb.limit(Math.min(off + len, bb.capacity()));
|
||||
bb.position(off);
|
||||
this.bb = bb;
|
||||
this.bs = bs;
|
||||
return read(bb);
|
||||
}
|
||||
|
||||
protected int read(ByteBuffer bb)
|
||||
throws IOException
|
||||
{
|
||||
return ChannelInputStream.read(ch, bb, true);
|
||||
}
|
||||
|
||||
public int available() throws IOException {
|
||||
// special case where the channel is to a file
|
||||
if (ch instanceof SeekableByteChannel) {
|
||||
SeekableByteChannel sbc = (SeekableByteChannel)ch;
|
||||
long rem = Math.max(0, sbc.size() - sbc.position());
|
||||
return (rem > Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int)rem;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
ch.close();
|
||||
}
|
||||
|
||||
}
|
||||
96
jdkSrc/jdk8/sun/nio/ch/CompletedFuture.java
Normal file
96
jdkSrc/jdk8/sun/nio/ch/CompletedFuture.java
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A Future representing the result of an I/O operation that has already
|
||||
* completed.
|
||||
*/
|
||||
|
||||
final class CompletedFuture<V> implements Future<V> {
|
||||
private final V result;
|
||||
private final Throwable exc;
|
||||
|
||||
private CompletedFuture(V result, Throwable exc) {
|
||||
this.result = result;
|
||||
this.exc = exc;
|
||||
}
|
||||
|
||||
static <V> CompletedFuture<V> withResult(V result) {
|
||||
return new CompletedFuture<V>(result, null);
|
||||
}
|
||||
|
||||
static <V> CompletedFuture<V> withFailure(Throwable exc) {
|
||||
// exception must be IOException or SecurityException
|
||||
if (!(exc instanceof IOException) && !(exc instanceof SecurityException))
|
||||
exc = new IOException(exc);
|
||||
return new CompletedFuture<V>(null, exc);
|
||||
}
|
||||
|
||||
static <V> CompletedFuture<V> withResult(V result, Throwable exc) {
|
||||
if (exc == null) {
|
||||
return withResult(result);
|
||||
} else {
|
||||
return withFailure(exc);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get() throws ExecutionException {
|
||||
if (exc != null)
|
||||
throw new ExecutionException(exc);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(long timeout, TimeUnit unit) throws ExecutionException {
|
||||
if (unit == null)
|
||||
throw new NullPointerException();
|
||||
if (exc != null)
|
||||
throw new ExecutionException(exc);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
1159
jdkSrc/jdk8/sun/nio/ch/DatagramChannelImpl.java
Normal file
1159
jdkSrc/jdk8/sun/nio/ch/DatagramChannelImpl.java
Normal file
File diff suppressed because it is too large
Load Diff
73
jdkSrc/jdk8/sun/nio/ch/DatagramDispatcher.java
Normal file
73
jdkSrc/jdk8/sun/nio/ch/DatagramDispatcher.java
Normal file
@@ -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;
|
||||
}
|
||||
420
jdkSrc/jdk8/sun/nio/ch/DatagramSocketAdaptor.java
Normal file
420
jdkSrc/jdk8/sun/nio/ch/DatagramSocketAdaptor.java
Normal file
@@ -0,0 +1,420 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2018, 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.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.DatagramSocketImpl;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.SocketException;
|
||||
import java.net.SocketOption;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.StandardSocketOptions;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.DatagramChannel;
|
||||
import java.nio.channels.IllegalBlockingModeException;
|
||||
|
||||
|
||||
// Make a datagram-socket channel look like a datagram socket.
|
||||
//
|
||||
// The methods in this class are defined in exactly the same order as in
|
||||
// java.net.DatagramSocket so as to simplify tracking future changes to that
|
||||
// class.
|
||||
//
|
||||
|
||||
public class DatagramSocketAdaptor
|
||||
extends DatagramSocket
|
||||
{
|
||||
|
||||
// The channel being adapted
|
||||
private final DatagramChannelImpl dc;
|
||||
|
||||
// Timeout "option" value for receives
|
||||
private volatile int timeout = 0;
|
||||
|
||||
// ## super will create a useless impl
|
||||
private DatagramSocketAdaptor(DatagramChannelImpl dc) throws IOException {
|
||||
// Invoke the DatagramSocketAdaptor(SocketAddress) constructor,
|
||||
// passing a dummy DatagramSocketImpl object to aovid any native
|
||||
// resource allocation in super class and invoking our bind method
|
||||
// before the dc field is initialized.
|
||||
super(dummyDatagramSocket);
|
||||
this.dc = dc;
|
||||
}
|
||||
|
||||
public static DatagramSocket create(DatagramChannelImpl dc) {
|
||||
try {
|
||||
return new DatagramSocketAdaptor(dc);
|
||||
} catch (IOException x) {
|
||||
throw new Error(x);
|
||||
}
|
||||
}
|
||||
|
||||
private void connectInternal(SocketAddress remote)
|
||||
throws SocketException
|
||||
{
|
||||
InetSocketAddress isa = Net.asInetSocketAddress(remote);
|
||||
int port = isa.getPort();
|
||||
if (port < 0 || port > 0xFFFF)
|
||||
throw new IllegalArgumentException("connect: " + port);
|
||||
if (remote == null)
|
||||
throw new IllegalArgumentException("connect: null address");
|
||||
if (isClosed())
|
||||
return;
|
||||
try {
|
||||
dc.connect(remote);
|
||||
} catch (Exception x) {
|
||||
Net.translateToSocketException(x);
|
||||
}
|
||||
}
|
||||
|
||||
public void bind(SocketAddress local) throws SocketException {
|
||||
try {
|
||||
if (local == null)
|
||||
local = new InetSocketAddress(0);
|
||||
dc.bind(local);
|
||||
} catch (Exception x) {
|
||||
Net.translateToSocketException(x);
|
||||
}
|
||||
}
|
||||
|
||||
public void connect(InetAddress address, int port) {
|
||||
try {
|
||||
connectInternal(new InetSocketAddress(address, port));
|
||||
} catch (SocketException x) {
|
||||
// Yes, j.n.DatagramSocket really does this
|
||||
}
|
||||
}
|
||||
|
||||
public void connect(SocketAddress remote) throws SocketException {
|
||||
if (remote == null)
|
||||
throw new IllegalArgumentException("Address can't be null");
|
||||
connectInternal(remote);
|
||||
}
|
||||
|
||||
public void disconnect() {
|
||||
try {
|
||||
dc.disconnect();
|
||||
} catch (IOException x) {
|
||||
throw new Error(x);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isBound() {
|
||||
return dc.localAddress() != null;
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
return dc.remoteAddress() != null;
|
||||
}
|
||||
|
||||
public InetAddress getInetAddress() {
|
||||
return (isConnected()
|
||||
? Net.asInetSocketAddress(dc.remoteAddress()).getAddress()
|
||||
: null);
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return (isConnected()
|
||||
? Net.asInetSocketAddress(dc.remoteAddress()).getPort()
|
||||
: -1);
|
||||
}
|
||||
|
||||
public void send(DatagramPacket p) throws IOException {
|
||||
synchronized (dc.blockingLock()) {
|
||||
if (!dc.isBlocking())
|
||||
throw new IllegalBlockingModeException();
|
||||
try {
|
||||
synchronized (p) {
|
||||
ByteBuffer bb = ByteBuffer.wrap(p.getData(),
|
||||
p.getOffset(),
|
||||
p.getLength());
|
||||
if (dc.isConnected()) {
|
||||
if (p.getAddress() == null) {
|
||||
// Legacy DatagramSocket will send in this case
|
||||
// and set address and port of the packet
|
||||
InetSocketAddress isa = (InetSocketAddress)
|
||||
dc.remoteAddress();
|
||||
p.setPort(isa.getPort());
|
||||
p.setAddress(isa.getAddress());
|
||||
dc.write(bb);
|
||||
} else {
|
||||
// Target address may not match connected address
|
||||
dc.send(bb, p.getSocketAddress());
|
||||
}
|
||||
} else {
|
||||
// Not connected so address must be valid or throw
|
||||
dc.send(bb, p.getSocketAddress());
|
||||
}
|
||||
}
|
||||
} catch (IOException x) {
|
||||
Net.translateException(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Must hold dc.blockingLock()
|
||||
//
|
||||
private SocketAddress receive(ByteBuffer bb) throws IOException {
|
||||
if (timeout == 0) {
|
||||
return dc.receive(bb);
|
||||
}
|
||||
|
||||
dc.configureBlocking(false);
|
||||
try {
|
||||
SocketAddress sender;
|
||||
if ((sender = dc.receive(bb)) != null)
|
||||
return sender;
|
||||
long to = timeout;
|
||||
for (;;) {
|
||||
if (!dc.isOpen())
|
||||
throw new ClosedChannelException();
|
||||
long st = System.currentTimeMillis();
|
||||
int result = dc.poll(Net.POLLIN, to);
|
||||
if (result > 0 && ((result & Net.POLLIN) != 0)) {
|
||||
if ((sender = dc.receive(bb)) != null)
|
||||
return sender;
|
||||
}
|
||||
to -= System.currentTimeMillis() - st;
|
||||
if (to <= 0)
|
||||
throw new SocketTimeoutException();
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
dc.configureBlocking(true);
|
||||
} catch (ClosedChannelException e) { }
|
||||
}
|
||||
}
|
||||
|
||||
public void receive(DatagramPacket p) throws IOException {
|
||||
synchronized (dc.blockingLock()) {
|
||||
if (!dc.isBlocking())
|
||||
throw new IllegalBlockingModeException();
|
||||
try {
|
||||
synchronized (p) {
|
||||
ByteBuffer bb = ByteBuffer.wrap(p.getData(),
|
||||
p.getOffset(),
|
||||
p.getLength());
|
||||
SocketAddress sender = receive(bb);
|
||||
p.setSocketAddress(sender);
|
||||
p.setLength(bb.position() - p.getOffset());
|
||||
}
|
||||
} catch (IOException x) {
|
||||
Net.translateException(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public InetAddress getLocalAddress() {
|
||||
if (isClosed())
|
||||
return null;
|
||||
SocketAddress local = dc.localAddress();
|
||||
if (local == null)
|
||||
local = new InetSocketAddress(0);
|
||||
InetAddress result = ((InetSocketAddress)local).getAddress();
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
try {
|
||||
sm.checkConnect(result.getHostAddress(), -1);
|
||||
} catch (SecurityException x) {
|
||||
return new InetSocketAddress(0).getAddress();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public int getLocalPort() {
|
||||
if (isClosed())
|
||||
return -1;
|
||||
try {
|
||||
SocketAddress local = dc.getLocalAddress();
|
||||
if (local != null) {
|
||||
return ((InetSocketAddress)local).getPort();
|
||||
}
|
||||
} catch (Exception x) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setSoTimeout(int timeout) throws SocketException {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
public int getSoTimeout() throws SocketException {
|
||||
return timeout;
|
||||
}
|
||||
|
||||
private void setBooleanOption(SocketOption<Boolean> name, boolean value)
|
||||
throws SocketException
|
||||
{
|
||||
try {
|
||||
dc.setOption(name, value);
|
||||
} catch (IOException x) {
|
||||
Net.translateToSocketException(x);
|
||||
}
|
||||
}
|
||||
|
||||
private void setIntOption(SocketOption<Integer> name, int value)
|
||||
throws SocketException
|
||||
{
|
||||
try {
|
||||
dc.setOption(name, value);
|
||||
} catch (IOException x) {
|
||||
Net.translateToSocketException(x);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean getBooleanOption(SocketOption<Boolean> name) throws SocketException {
|
||||
try {
|
||||
return dc.getOption(name).booleanValue();
|
||||
} catch (IOException x) {
|
||||
Net.translateToSocketException(x);
|
||||
return false; // keep compiler happy
|
||||
}
|
||||
}
|
||||
|
||||
private int getIntOption(SocketOption<Integer> name) throws SocketException {
|
||||
try {
|
||||
return dc.getOption(name).intValue();
|
||||
} catch (IOException x) {
|
||||
Net.translateToSocketException(x);
|
||||
return -1; // keep compiler happy
|
||||
}
|
||||
}
|
||||
|
||||
public void setSendBufferSize(int size) throws SocketException {
|
||||
if (size <= 0)
|
||||
throw new IllegalArgumentException("Invalid send size");
|
||||
setIntOption(StandardSocketOptions.SO_SNDBUF, size);
|
||||
}
|
||||
|
||||
public int getSendBufferSize() throws SocketException {
|
||||
return getIntOption(StandardSocketOptions.SO_SNDBUF);
|
||||
}
|
||||
|
||||
public void setReceiveBufferSize(int size) throws SocketException {
|
||||
if (size <= 0)
|
||||
throw new IllegalArgumentException("Invalid receive size");
|
||||
setIntOption(StandardSocketOptions.SO_RCVBUF, size);
|
||||
}
|
||||
|
||||
public int getReceiveBufferSize() throws SocketException {
|
||||
return getIntOption(StandardSocketOptions.SO_RCVBUF);
|
||||
}
|
||||
|
||||
public void setReuseAddress(boolean on) throws SocketException {
|
||||
setBooleanOption(StandardSocketOptions.SO_REUSEADDR, on);
|
||||
}
|
||||
|
||||
public boolean getReuseAddress() throws SocketException {
|
||||
return getBooleanOption(StandardSocketOptions.SO_REUSEADDR);
|
||||
|
||||
}
|
||||
|
||||
public void setBroadcast(boolean on) throws SocketException {
|
||||
setBooleanOption(StandardSocketOptions.SO_BROADCAST, on);
|
||||
}
|
||||
|
||||
public boolean getBroadcast() throws SocketException {
|
||||
return getBooleanOption(StandardSocketOptions.SO_BROADCAST);
|
||||
}
|
||||
|
||||
public void setTrafficClass(int tc) throws SocketException {
|
||||
setIntOption(StandardSocketOptions.IP_TOS, tc);
|
||||
}
|
||||
|
||||
public int getTrafficClass() throws SocketException {
|
||||
return getIntOption(StandardSocketOptions.IP_TOS);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
try {
|
||||
dc.close();
|
||||
} catch (IOException x) {
|
||||
throw new Error(x);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isClosed() {
|
||||
return !dc.isOpen();
|
||||
}
|
||||
|
||||
public DatagramChannel getChannel() {
|
||||
return dc;
|
||||
}
|
||||
|
||||
/*
|
||||
* A dummy implementation of DatagramSocketImpl that can be passed to the
|
||||
* DatagramSocket constructor so that no native resources are allocated in
|
||||
* super class.
|
||||
*/
|
||||
private static final DatagramSocketImpl dummyDatagramSocket
|
||||
= new DatagramSocketImpl()
|
||||
{
|
||||
protected void create() throws SocketException {}
|
||||
|
||||
protected void bind(int lport, InetAddress laddr) throws SocketException {}
|
||||
|
||||
protected void send(DatagramPacket p) throws IOException {}
|
||||
|
||||
protected int peek(InetAddress i) throws IOException { return 0; }
|
||||
|
||||
protected int peekData(DatagramPacket p) throws IOException { return 0; }
|
||||
|
||||
protected void receive(DatagramPacket p) throws IOException {}
|
||||
|
||||
@Deprecated
|
||||
protected void setTTL(byte ttl) throws IOException {}
|
||||
|
||||
@Deprecated
|
||||
protected byte getTTL() throws IOException { return 0; }
|
||||
|
||||
protected void setTimeToLive(int ttl) throws IOException {}
|
||||
|
||||
protected int getTimeToLive() throws IOException { return 0;}
|
||||
|
||||
protected void join(InetAddress inetaddr) throws IOException {}
|
||||
|
||||
protected void leave(InetAddress inetaddr) throws IOException {}
|
||||
|
||||
protected void joinGroup(SocketAddress mcastaddr,
|
||||
NetworkInterface netIf) throws IOException {}
|
||||
|
||||
protected void leaveGroup(SocketAddress mcastaddr,
|
||||
NetworkInterface netIf) throws IOException {}
|
||||
|
||||
protected void close() {}
|
||||
|
||||
public Object getOption(int optID) throws SocketException { return null;}
|
||||
|
||||
public void setOption(int optID, Object value) throws SocketException {}
|
||||
};
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
49
jdkSrc/jdk8/sun/nio/ch/DefaultSelectorProvider.java
Normal file
49
jdkSrc/jdk8/sun/nio/ch/DefaultSelectorProvider.java
Normal file
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
39
jdkSrc/jdk8/sun/nio/ch/DirectBuffer.java
Normal file
39
jdkSrc/jdk8/sun/nio/ch/DirectBuffer.java
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 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 sun.misc.Cleaner;
|
||||
|
||||
|
||||
public interface DirectBuffer {
|
||||
|
||||
public long address();
|
||||
|
||||
public Object attachment();
|
||||
|
||||
public Cleaner cleaner();
|
||||
|
||||
}
|
||||
44
jdkSrc/jdk8/sun/nio/ch/ExtendedSocketOption.java
Normal file
44
jdkSrc/jdk8/sun/nio/ch/ExtendedSocketOption.java
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.net.SocketOption;
|
||||
|
||||
/**
|
||||
* Defines socket options that are supported by the implementation
|
||||
* but not defined in StandardSocketOptions.
|
||||
*/
|
||||
|
||||
class ExtendedSocketOption {
|
||||
private ExtendedSocketOption() { }
|
||||
|
||||
static final SocketOption<Boolean> SO_OOBINLINE =
|
||||
new SocketOption<Boolean>() {
|
||||
public String name() { return "SO_OOBINLINE"; }
|
||||
public Class<Boolean> type() { return Boolean.class; }
|
||||
public String toString() { return name(); }
|
||||
};
|
||||
}
|
||||
1222
jdkSrc/jdk8/sun/nio/ch/FileChannelImpl.java
Normal file
1222
jdkSrc/jdk8/sun/nio/ch/FileChannelImpl.java
Normal file
File diff suppressed because it is too large
Load Diff
69
jdkSrc/jdk8/sun/nio/ch/FileDispatcher.java
Normal file
69
jdkSrc/jdk8/sun/nio/ch/FileDispatcher.java
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2018, 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 java.nio.channels.SelectableChannel;
|
||||
|
||||
abstract class FileDispatcher extends NativeDispatcher {
|
||||
|
||||
public static final int NO_LOCK = -1; // Failed to lock
|
||||
public static final int LOCKED = 0; // Obtained requested lock
|
||||
public static final int RET_EX_LOCK = 1; // Obtained exclusive lock
|
||||
public static final int INTERRUPTED = 2; // Request interrupted
|
||||
|
||||
/**
|
||||
* Sets or reports this file's position
|
||||
* If offset is -1, the current position is returned
|
||||
* otherwise the position is set to offset.
|
||||
*/
|
||||
abstract long seek(FileDescriptor fd, long offset) throws IOException;
|
||||
|
||||
abstract int force(FileDescriptor fd, boolean metaData) throws IOException;
|
||||
|
||||
abstract int truncate(FileDescriptor fd, long size) throws IOException;
|
||||
|
||||
abstract long size(FileDescriptor fd) throws IOException;
|
||||
|
||||
abstract int lock(FileDescriptor fd, boolean blocking, long pos, long size,
|
||||
boolean shared) throws IOException;
|
||||
|
||||
abstract void release(FileDescriptor fd, long pos, long size)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Returns a dup of fd if a file descriptor is required for
|
||||
* memory-mapping operations, otherwise returns an invalid
|
||||
* FileDescriptor (meaning a newly allocated FileDescriptor)
|
||||
*/
|
||||
abstract FileDescriptor duplicateForMapping(FileDescriptor fd)
|
||||
throws IOException;
|
||||
|
||||
abstract boolean canTransferToDirectly(SelectableChannel sc);
|
||||
|
||||
abstract boolean transferToDirectlyNeedsPositionLock();
|
||||
}
|
||||
199
jdkSrc/jdk8/sun/nio/ch/FileDispatcherImpl.java
Normal file
199
jdkSrc/jdk8/sun/nio/ch/FileDispatcherImpl.java
Normal file
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2018, 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 java.security.PrivilegedAction;
|
||||
import sun.misc.SharedSecrets;
|
||||
import sun.misc.JavaIOFileDescriptorAccess;
|
||||
|
||||
class FileDispatcherImpl extends FileDispatcher {
|
||||
|
||||
// set to true if fast file transmission (TransmitFile) is enabled
|
||||
private static final boolean fastFileTransfer;
|
||||
|
||||
/**
|
||||
* Indicates if the dispatcher should first advance the file position
|
||||
* to the end of file when writing.
|
||||
*/
|
||||
private final boolean append;
|
||||
|
||||
FileDispatcherImpl(boolean append) {
|
||||
this.append = append;
|
||||
}
|
||||
|
||||
FileDispatcherImpl() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
@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, append);
|
||||
}
|
||||
|
||||
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, append);
|
||||
}
|
||||
|
||||
long seek(FileDescriptor fd, long offset) throws IOException {
|
||||
return seek0(fd, offset);
|
||||
}
|
||||
|
||||
int force(FileDescriptor fd, boolean metaData) throws IOException {
|
||||
return force0(fd, metaData);
|
||||
}
|
||||
|
||||
int truncate(FileDescriptor fd, long size) throws IOException {
|
||||
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
|
||||
JavaIOFileDescriptorAccess fdAccess =
|
||||
SharedSecrets.getJavaIOFileDescriptorAccess();
|
||||
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 = java.security.AccessController.doPrivileged(
|
||||
new PrivilegedAction<String>() {
|
||||
@Override
|
||||
public String run() {
|
||||
return System.getProperty("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 long seek0(FileDescriptor fd, long offset) 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 void closeByHandle(long fd) throws IOException;
|
||||
|
||||
static native long duplicateHandle(long fd) throws IOException;
|
||||
}
|
||||
79
jdkSrc/jdk8/sun/nio/ch/FileKey.java
Normal file
79
jdkSrc/jdk8/sun/nio/ch/FileKey.java
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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) {
|
||||
FileKey fk = new FileKey();
|
||||
try {
|
||||
fk.init(fd);
|
||||
} catch (IOException ioe) {
|
||||
throw new Error(ioe);
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
68
jdkSrc/jdk8/sun/nio/ch/FileLockImpl.java
Normal file
68
jdkSrc/jdk8/sun/nio/ch/FileLockImpl.java
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 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.io.IOException;
|
||||
import java.nio.channels.*;
|
||||
|
||||
public class FileLockImpl
|
||||
extends FileLock
|
||||
{
|
||||
private volatile boolean valid = true;
|
||||
|
||||
FileLockImpl(FileChannel channel, long position, long size, boolean shared)
|
||||
{
|
||||
super(channel, position, size, shared);
|
||||
}
|
||||
|
||||
FileLockImpl(AsynchronousFileChannel channel, long position, long size, boolean shared)
|
||||
{
|
||||
super(channel, position, size, shared);
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return valid;
|
||||
}
|
||||
|
||||
void invalidate() {
|
||||
assert Thread.holdsLock(this);
|
||||
valid = false;
|
||||
}
|
||||
|
||||
public synchronized void release() throws IOException {
|
||||
Channel ch = acquiredBy();
|
||||
if (!ch.isOpen())
|
||||
throw new ClosedChannelException();
|
||||
if (valid) {
|
||||
if (ch instanceof FileChannelImpl)
|
||||
((FileChannelImpl)ch).release(this);
|
||||
else if (ch instanceof AsynchronousFileChannelImpl)
|
||||
((AsynchronousFileChannelImpl)ch).release(this);
|
||||
else throw new AssertionError();
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
273
jdkSrc/jdk8/sun/nio/ch/FileLockTable.java
Normal file
273
jdkSrc/jdk8/sun/nio/ch/FileLockTable.java
Normal file
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 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.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.lang.ref.*;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
|
||||
abstract class FileLockTable {
|
||||
protected FileLockTable() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a file lock table for a channel that is connected to
|
||||
* the a system-wide map of all file locks for the Java virtual machine.
|
||||
*/
|
||||
public static FileLockTable newSharedFileLockTable(Channel channel,
|
||||
FileDescriptor fd)
|
||||
throws IOException
|
||||
{
|
||||
return new SharedFileLockTable(channel, fd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a file lock to the table.
|
||||
*
|
||||
* @throws OverlappingFileLockException if the file lock overlaps
|
||||
* with an existing file lock in the table
|
||||
*/
|
||||
public abstract void add(FileLock fl) throws OverlappingFileLockException;
|
||||
|
||||
/**
|
||||
* Remove an existing file lock from the table.
|
||||
*/
|
||||
public abstract void remove(FileLock fl);
|
||||
|
||||
/**
|
||||
* Removes all file locks from the table.
|
||||
*
|
||||
* @return The list of file locks removed
|
||||
*/
|
||||
public abstract List<FileLock> removeAll();
|
||||
|
||||
/**
|
||||
* Replaces an existing file lock in the table.
|
||||
*/
|
||||
public abstract void replace(FileLock fl1, FileLock fl2);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A file lock table that is over a system-wide map of all file locks.
|
||||
*/
|
||||
class SharedFileLockTable extends FileLockTable {
|
||||
|
||||
/**
|
||||
* A weak reference to a FileLock.
|
||||
* <p>
|
||||
* SharedFileLockTable uses a list of file lock references to avoid keeping the
|
||||
* FileLock (and FileChannel) alive.
|
||||
*/
|
||||
private static class FileLockReference extends WeakReference<FileLock> {
|
||||
private FileKey fileKey;
|
||||
|
||||
FileLockReference(FileLock referent,
|
||||
ReferenceQueue<FileLock> queue,
|
||||
FileKey key) {
|
||||
super(referent, queue);
|
||||
this.fileKey = key;
|
||||
}
|
||||
|
||||
FileKey fileKey() {
|
||||
return fileKey;
|
||||
}
|
||||
}
|
||||
|
||||
// The system-wide map is a ConcurrentHashMap that is keyed on the FileKey.
|
||||
// The map value is a list of file locks represented by FileLockReferences.
|
||||
// All access to the list must be synchronized on the list.
|
||||
private static ConcurrentHashMap<FileKey, List<FileLockReference>> lockMap =
|
||||
new ConcurrentHashMap<FileKey, List<FileLockReference>>();
|
||||
|
||||
// reference queue for cleared refs
|
||||
private static ReferenceQueue<FileLock> queue = new ReferenceQueue<FileLock>();
|
||||
|
||||
// The connection to which this table is connected
|
||||
private final Channel channel;
|
||||
|
||||
// File key for the file that this channel is connected to
|
||||
private final FileKey fileKey;
|
||||
|
||||
SharedFileLockTable(Channel channel, FileDescriptor fd) throws IOException {
|
||||
this.channel = channel;
|
||||
this.fileKey = FileKey.create(fd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(FileLock fl) throws OverlappingFileLockException {
|
||||
List<FileLockReference> list = lockMap.get(fileKey);
|
||||
|
||||
for (;;) {
|
||||
|
||||
// The key isn't in the map so we try to create it atomically
|
||||
if (list == null) {
|
||||
list = new ArrayList<FileLockReference>(2);
|
||||
List<FileLockReference> prev;
|
||||
synchronized (list) {
|
||||
prev = lockMap.putIfAbsent(fileKey, list);
|
||||
if (prev == null) {
|
||||
// we successfully created the key so we add the file lock
|
||||
list.add(new FileLockReference(fl, queue, fileKey));
|
||||
break;
|
||||
}
|
||||
}
|
||||
// someone else got there first
|
||||
list = prev;
|
||||
}
|
||||
|
||||
// There is already a key. It is possible that some other thread
|
||||
// is removing it so we re-fetch the value from the map. If it
|
||||
// hasn't changed then we check the list for overlapping locks
|
||||
// and add the new lock to the list.
|
||||
synchronized (list) {
|
||||
List<FileLockReference> current = lockMap.get(fileKey);
|
||||
if (list == current) {
|
||||
checkList(list, fl.position(), fl.size());
|
||||
list.add(new FileLockReference(fl, queue, fileKey));
|
||||
break;
|
||||
}
|
||||
list = current;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// process any stale entries pending in the reference queue
|
||||
removeStaleEntries();
|
||||
}
|
||||
|
||||
private void removeKeyIfEmpty(FileKey fk, List<FileLockReference> list) {
|
||||
assert Thread.holdsLock(list);
|
||||
assert lockMap.get(fk) == list;
|
||||
if (list.isEmpty()) {
|
||||
lockMap.remove(fk);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(FileLock fl) {
|
||||
assert fl != null;
|
||||
|
||||
// the lock must exist so the list of locks must be present
|
||||
List<FileLockReference> list = lockMap.get(fileKey);
|
||||
if (list == null) return;
|
||||
|
||||
synchronized (list) {
|
||||
int index = 0;
|
||||
while (index < list.size()) {
|
||||
FileLockReference ref = list.get(index);
|
||||
FileLock lock = ref.get();
|
||||
if (lock == fl) {
|
||||
assert (lock != null) && (lock.acquiredBy() == channel);
|
||||
ref.clear();
|
||||
list.remove(index);
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FileLock> removeAll() {
|
||||
List<FileLock> result = new ArrayList<FileLock>();
|
||||
List<FileLockReference> list = lockMap.get(fileKey);
|
||||
if (list != null) {
|
||||
synchronized (list) {
|
||||
int index = 0;
|
||||
while (index < list.size()) {
|
||||
FileLockReference ref = list.get(index);
|
||||
FileLock lock = ref.get();
|
||||
|
||||
// remove locks obtained by this channel
|
||||
if (lock != null && lock.acquiredBy() == channel) {
|
||||
// remove the lock from the list
|
||||
ref.clear();
|
||||
list.remove(index);
|
||||
|
||||
// add to result
|
||||
result.add(lock);
|
||||
} else {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
// once the lock list is empty we remove it from the map
|
||||
removeKeyIfEmpty(fileKey, list);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replace(FileLock fromLock, FileLock toLock) {
|
||||
// the lock must exist so there must be a list
|
||||
List<FileLockReference> list = lockMap.get(fileKey);
|
||||
assert list != null;
|
||||
|
||||
synchronized (list) {
|
||||
for (int index=0; index<list.size(); index++) {
|
||||
FileLockReference ref = list.get(index);
|
||||
FileLock lock = ref.get();
|
||||
if (lock == fromLock) {
|
||||
ref.clear();
|
||||
list.set(index, new FileLockReference(toLock, queue, fileKey));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for overlapping file locks
|
||||
private void checkList(List<FileLockReference> list, long position, long size)
|
||||
throws OverlappingFileLockException
|
||||
{
|
||||
assert Thread.holdsLock(list);
|
||||
for (FileLockReference ref: list) {
|
||||
FileLock fl = ref.get();
|
||||
if (fl != null && fl.overlaps(position, size))
|
||||
throw new OverlappingFileLockException();
|
||||
}
|
||||
}
|
||||
|
||||
// Process the reference queue
|
||||
private void removeStaleEntries() {
|
||||
FileLockReference ref;
|
||||
while ((ref = (FileLockReference)queue.poll()) != null) {
|
||||
FileKey fk = ref.fileKey();
|
||||
List<FileLockReference> list = lockMap.get(fk);
|
||||
if (list != null) {
|
||||
synchronized (list) {
|
||||
list.remove(ref);
|
||||
removeKeyIfEmpty(fk, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
35
jdkSrc/jdk8/sun/nio/ch/Groupable.java
Normal file
35
jdkSrc/jdk8/sun/nio/ch/Groupable.java
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Implemented by asynchronous channels that can be associated with an
|
||||
* asynchronous channel group.
|
||||
*/
|
||||
|
||||
interface Groupable {
|
||||
AsynchronousChannelGroupImpl group();
|
||||
}
|
||||
84
jdkSrc/jdk8/sun/nio/ch/IOStatus.java
Normal file
84
jdkSrc/jdk8/sun/nio/ch/IOStatus.java
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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.lang.annotation.Native;
|
||||
|
||||
// Constants for reporting I/O status
|
||||
|
||||
public final class IOStatus {
|
||||
|
||||
private IOStatus() { }
|
||||
|
||||
@Native public static final int EOF = -1; // End of file
|
||||
@Native public static final int UNAVAILABLE = -2; // Nothing available (non-blocking)
|
||||
@Native public static final int INTERRUPTED = -3; // System call interrupted
|
||||
@Native public static final int UNSUPPORTED = -4; // Operation not supported
|
||||
@Native public static final int THROWN = -5; // Exception thrown in JNI code
|
||||
@Native public static final int UNSUPPORTED_CASE = -6; // This case not supported
|
||||
|
||||
// The following two methods are for use in try/finally blocks where a
|
||||
// status value needs to be normalized before being returned to the invoker
|
||||
// but also checked for illegal negative values before the return
|
||||
// completes, like so:
|
||||
//
|
||||
// int n = 0;
|
||||
// try {
|
||||
// begin();
|
||||
// n = op(fd, buf, ...);
|
||||
// return IOStatus.normalize(n); // Converts UNAVAILABLE to zero
|
||||
// } finally {
|
||||
// end(n > 0);
|
||||
// assert IOStatus.check(n); // Checks other negative values
|
||||
// }
|
||||
//
|
||||
|
||||
public static int normalize(int n) {
|
||||
if (n == UNAVAILABLE)
|
||||
return 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
public static boolean check(int n) {
|
||||
return (n >= UNAVAILABLE);
|
||||
}
|
||||
|
||||
public static long normalize(long n) {
|
||||
if (n == UNAVAILABLE)
|
||||
return 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
public static boolean check(long n) {
|
||||
return (n >= UNAVAILABLE);
|
||||
}
|
||||
|
||||
// Return true iff n is not one of the IOStatus values
|
||||
public static boolean checkAll(long n) {
|
||||
return ((n > EOF) || (n < UNSUPPORTED_CASE));
|
||||
}
|
||||
|
||||
}
|
||||
370
jdkSrc/jdk8/sun/nio/ch/IOUtil.java
Normal file
370
jdkSrc/jdk8/sun/nio/ch/IOUtil.java
Normal file
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* 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.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
|
||||
/**
|
||||
* File-descriptor based I/O utilities that are shared by NIO classes.
|
||||
*/
|
||||
|
||||
public class IOUtil {
|
||||
|
||||
/**
|
||||
* Max number of iovec structures that readv/writev supports
|
||||
*/
|
||||
static final int IOV_MAX;
|
||||
|
||||
private IOUtil() { } // No instantiation
|
||||
|
||||
static int write(FileDescriptor fd, ByteBuffer src, long position,
|
||||
NativeDispatcher nd)
|
||||
throws IOException
|
||||
{
|
||||
if (src instanceof DirectBuffer)
|
||||
return writeFromNativeBuffer(fd, src, position, nd);
|
||||
|
||||
// Substitute a native buffer
|
||||
int pos = src.position();
|
||||
int lim = src.limit();
|
||||
assert (pos <= lim);
|
||||
int rem = (pos <= lim ? lim - pos : 0);
|
||||
ByteBuffer bb = Util.getTemporaryDirectBuffer(rem);
|
||||
try {
|
||||
bb.put(src);
|
||||
bb.flip();
|
||||
// Do not update src until we see how many bytes were written
|
||||
src.position(pos);
|
||||
|
||||
int n = writeFromNativeBuffer(fd, bb, position, nd);
|
||||
if (n > 0) {
|
||||
// now update src
|
||||
src.position(pos + n);
|
||||
}
|
||||
return n;
|
||||
} finally {
|
||||
Util.offerFirstTemporaryDirectBuffer(bb);
|
||||
}
|
||||
}
|
||||
|
||||
private static int writeFromNativeBuffer(FileDescriptor fd, ByteBuffer bb,
|
||||
long position, NativeDispatcher nd)
|
||||
throws IOException
|
||||
{
|
||||
int pos = bb.position();
|
||||
int lim = bb.limit();
|
||||
assert (pos <= lim);
|
||||
int rem = (pos <= lim ? lim - pos : 0);
|
||||
|
||||
int written = 0;
|
||||
if (rem == 0)
|
||||
return 0;
|
||||
if (position != -1) {
|
||||
written = nd.pwrite(fd,
|
||||
((DirectBuffer)bb).address() + pos,
|
||||
rem, position);
|
||||
} else {
|
||||
written = nd.write(fd, ((DirectBuffer)bb).address() + pos, rem);
|
||||
}
|
||||
if (written > 0)
|
||||
bb.position(pos + written);
|
||||
return written;
|
||||
}
|
||||
|
||||
static long write(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd)
|
||||
throws IOException
|
||||
{
|
||||
return write(fd, bufs, 0, bufs.length, nd);
|
||||
}
|
||||
|
||||
static long write(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,
|
||||
NativeDispatcher nd)
|
||||
throws IOException
|
||||
{
|
||||
IOVecWrapper vec = IOVecWrapper.get(length);
|
||||
|
||||
boolean completed = false;
|
||||
int iov_len = 0;
|
||||
try {
|
||||
|
||||
// Iterate over buffers to populate native iovec array.
|
||||
int count = offset + length;
|
||||
int i = offset;
|
||||
while (i < count && iov_len < IOV_MAX) {
|
||||
ByteBuffer buf = bufs[i];
|
||||
int pos = buf.position();
|
||||
int lim = buf.limit();
|
||||
assert (pos <= lim);
|
||||
int rem = (pos <= lim ? lim - pos : 0);
|
||||
if (rem > 0) {
|
||||
vec.setBuffer(iov_len, buf, pos, rem);
|
||||
|
||||
// allocate shadow buffer to ensure I/O is done with direct buffer
|
||||
if (!(buf instanceof DirectBuffer)) {
|
||||
ByteBuffer shadow = Util.getTemporaryDirectBuffer(rem);
|
||||
shadow.put(buf);
|
||||
shadow.flip();
|
||||
vec.setShadow(iov_len, shadow);
|
||||
buf.position(pos); // temporarily restore position in user buffer
|
||||
buf = shadow;
|
||||
pos = shadow.position();
|
||||
}
|
||||
|
||||
vec.putBase(iov_len, ((DirectBuffer)buf).address() + pos);
|
||||
vec.putLen(iov_len, rem);
|
||||
iov_len++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (iov_len == 0)
|
||||
return 0L;
|
||||
|
||||
long bytesWritten = nd.writev(fd, vec.address, iov_len);
|
||||
|
||||
// Notify the buffers how many bytes were taken
|
||||
long left = bytesWritten;
|
||||
for (int j=0; j<iov_len; j++) {
|
||||
if (left > 0) {
|
||||
ByteBuffer buf = vec.getBuffer(j);
|
||||
int pos = vec.getPosition(j);
|
||||
int rem = vec.getRemaining(j);
|
||||
int n = (left > rem) ? rem : (int)left;
|
||||
buf.position(pos + n);
|
||||
left -= n;
|
||||
}
|
||||
// return shadow buffers to buffer pool
|
||||
ByteBuffer shadow = vec.getShadow(j);
|
||||
if (shadow != null)
|
||||
Util.offerLastTemporaryDirectBuffer(shadow);
|
||||
vec.clearRefs(j);
|
||||
}
|
||||
|
||||
completed = true;
|
||||
return bytesWritten;
|
||||
|
||||
} finally {
|
||||
// if an error occurred then clear refs to buffers and return any shadow
|
||||
// buffers to cache
|
||||
if (!completed) {
|
||||
for (int j=0; j<iov_len; j++) {
|
||||
ByteBuffer shadow = vec.getShadow(j);
|
||||
if (shadow != null)
|
||||
Util.offerLastTemporaryDirectBuffer(shadow);
|
||||
vec.clearRefs(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int read(FileDescriptor fd, ByteBuffer dst, long position,
|
||||
NativeDispatcher nd)
|
||||
throws IOException
|
||||
{
|
||||
if (dst.isReadOnly())
|
||||
throw new IllegalArgumentException("Read-only buffer");
|
||||
if (dst instanceof DirectBuffer)
|
||||
return readIntoNativeBuffer(fd, dst, position, nd);
|
||||
|
||||
// Substitute a native buffer
|
||||
ByteBuffer bb = Util.getTemporaryDirectBuffer(dst.remaining());
|
||||
try {
|
||||
int n = readIntoNativeBuffer(fd, bb, position, nd);
|
||||
bb.flip();
|
||||
if (n > 0)
|
||||
dst.put(bb);
|
||||
return n;
|
||||
} finally {
|
||||
Util.offerFirstTemporaryDirectBuffer(bb);
|
||||
}
|
||||
}
|
||||
|
||||
private static int readIntoNativeBuffer(FileDescriptor fd, ByteBuffer bb,
|
||||
long position, NativeDispatcher nd)
|
||||
throws IOException
|
||||
{
|
||||
int pos = bb.position();
|
||||
int lim = bb.limit();
|
||||
assert (pos <= lim);
|
||||
int rem = (pos <= lim ? lim - pos : 0);
|
||||
|
||||
if (rem == 0)
|
||||
return 0;
|
||||
int n = 0;
|
||||
if (position != -1) {
|
||||
n = nd.pread(fd, ((DirectBuffer)bb).address() + pos,
|
||||
rem, position);
|
||||
} else {
|
||||
n = nd.read(fd, ((DirectBuffer)bb).address() + pos, rem);
|
||||
}
|
||||
if (n > 0)
|
||||
bb.position(pos + n);
|
||||
return n;
|
||||
}
|
||||
|
||||
static long read(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd)
|
||||
throws IOException
|
||||
{
|
||||
return read(fd, bufs, 0, bufs.length, nd);
|
||||
}
|
||||
|
||||
static long read(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,
|
||||
NativeDispatcher nd)
|
||||
throws IOException
|
||||
{
|
||||
IOVecWrapper vec = IOVecWrapper.get(length);
|
||||
|
||||
boolean completed = false;
|
||||
int iov_len = 0;
|
||||
try {
|
||||
|
||||
// Iterate over buffers to populate native iovec array.
|
||||
int count = offset + length;
|
||||
int i = offset;
|
||||
while (i < count && iov_len < IOV_MAX) {
|
||||
ByteBuffer buf = bufs[i];
|
||||
if (buf.isReadOnly())
|
||||
throw new IllegalArgumentException("Read-only buffer");
|
||||
int pos = buf.position();
|
||||
int lim = buf.limit();
|
||||
assert (pos <= lim);
|
||||
int rem = (pos <= lim ? lim - pos : 0);
|
||||
|
||||
if (rem > 0) {
|
||||
vec.setBuffer(iov_len, buf, pos, rem);
|
||||
|
||||
// allocate shadow buffer to ensure I/O is done with direct buffer
|
||||
if (!(buf instanceof DirectBuffer)) {
|
||||
ByteBuffer shadow = Util.getTemporaryDirectBuffer(rem);
|
||||
vec.setShadow(iov_len, shadow);
|
||||
buf = shadow;
|
||||
pos = shadow.position();
|
||||
}
|
||||
|
||||
vec.putBase(iov_len, ((DirectBuffer)buf).address() + pos);
|
||||
vec.putLen(iov_len, rem);
|
||||
iov_len++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (iov_len == 0)
|
||||
return 0L;
|
||||
|
||||
long bytesRead = nd.readv(fd, vec.address, iov_len);
|
||||
|
||||
// Notify the buffers how many bytes were read
|
||||
long left = bytesRead;
|
||||
for (int j=0; j<iov_len; j++) {
|
||||
ByteBuffer shadow = vec.getShadow(j);
|
||||
if (left > 0) {
|
||||
ByteBuffer buf = vec.getBuffer(j);
|
||||
int rem = vec.getRemaining(j);
|
||||
int n = (left > rem) ? rem : (int)left;
|
||||
if (shadow == null) {
|
||||
int pos = vec.getPosition(j);
|
||||
buf.position(pos + n);
|
||||
} else {
|
||||
shadow.limit(shadow.position() + n);
|
||||
buf.put(shadow);
|
||||
}
|
||||
left -= n;
|
||||
}
|
||||
if (shadow != null)
|
||||
Util.offerLastTemporaryDirectBuffer(shadow);
|
||||
vec.clearRefs(j);
|
||||
}
|
||||
|
||||
completed = true;
|
||||
return bytesRead;
|
||||
|
||||
} finally {
|
||||
// if an error occurred then clear refs to buffers and return any shadow
|
||||
// buffers to cache
|
||||
if (!completed) {
|
||||
for (int j=0; j<iov_len; j++) {
|
||||
ByteBuffer shadow = vec.getShadow(j);
|
||||
if (shadow != null)
|
||||
Util.offerLastTemporaryDirectBuffer(shadow);
|
||||
vec.clearRefs(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static FileDescriptor newFD(int i) {
|
||||
FileDescriptor fd = new FileDescriptor();
|
||||
setfdVal(fd, i);
|
||||
return fd;
|
||||
}
|
||||
|
||||
static native boolean randomBytes(byte[] someBytes);
|
||||
|
||||
/**
|
||||
* Returns two file descriptors for a pipe encoded in a long.
|
||||
* The read end of the pipe is returned in the high 32 bits,
|
||||
* while the write end is returned in the low 32 bits.
|
||||
*/
|
||||
static native long makePipe(boolean blocking);
|
||||
|
||||
static native boolean drain(int fd) throws IOException;
|
||||
|
||||
public static native void configureBlocking(FileDescriptor fd,
|
||||
boolean blocking)
|
||||
throws IOException;
|
||||
|
||||
public static native int fdVal(FileDescriptor fd);
|
||||
|
||||
static native void setfdVal(FileDescriptor fd, int value);
|
||||
|
||||
static native int fdLimit();
|
||||
|
||||
static native int iovMax();
|
||||
|
||||
static native void initIDs();
|
||||
|
||||
/**
|
||||
* Used to trigger loading of native libraries
|
||||
*/
|
||||
public static void load() { }
|
||||
|
||||
static {
|
||||
java.security.AccessController.doPrivileged(
|
||||
new java.security.PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
System.loadLibrary("net");
|
||||
System.loadLibrary("nio");
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
initIDs();
|
||||
|
||||
IOV_MAX = iovMax();
|
||||
}
|
||||
|
||||
}
|
||||
162
jdkSrc/jdk8/sun/nio/ch/IOVecWrapper.java
Normal file
162
jdkSrc/jdk8/sun/nio/ch/IOVecWrapper.java
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 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.ByteBuffer;
|
||||
import sun.misc.*;
|
||||
|
||||
|
||||
/**
|
||||
* Manipulates a native array of iovec structs on Solaris:
|
||||
*
|
||||
* typedef struct iovec {
|
||||
* caddr_t iov_base;
|
||||
int iov_len;
|
||||
* } iovec_t;
|
||||
*
|
||||
* @author Mike McCloskey
|
||||
* @since 1.4
|
||||
*/
|
||||
|
||||
class IOVecWrapper {
|
||||
|
||||
// Miscellaneous constants
|
||||
private static final int BASE_OFFSET = 0;
|
||||
private static final int LEN_OFFSET;
|
||||
private static final int SIZE_IOVEC;
|
||||
|
||||
// The iovec array
|
||||
private final AllocatedNativeObject vecArray;
|
||||
|
||||
// Number of elements in iovec array
|
||||
private final int size;
|
||||
|
||||
// Buffers and position/remaining corresponding to elements in iovec array
|
||||
private final ByteBuffer[] buf;
|
||||
private final int[] position;
|
||||
private final int[] remaining;
|
||||
|
||||
// Shadow buffers for cases when original buffer is substituted
|
||||
private final ByteBuffer[] shadow;
|
||||
|
||||
// Base address of this array
|
||||
final long address;
|
||||
|
||||
// Address size in bytes
|
||||
static int addressSize;
|
||||
|
||||
private static class Deallocator implements Runnable {
|
||||
private final AllocatedNativeObject obj;
|
||||
Deallocator(AllocatedNativeObject obj) {
|
||||
this.obj = obj;
|
||||
}
|
||||
public void run() {
|
||||
obj.free();
|
||||
}
|
||||
}
|
||||
|
||||
// per thread IOVecWrapper
|
||||
private static final ThreadLocal<IOVecWrapper> cached =
|
||||
new ThreadLocal<IOVecWrapper>();
|
||||
|
||||
private IOVecWrapper(int size) {
|
||||
this.size = size;
|
||||
this.buf = new ByteBuffer[size];
|
||||
this.position = new int[size];
|
||||
this.remaining = new int[size];
|
||||
this.shadow = new ByteBuffer[size];
|
||||
this.vecArray = new AllocatedNativeObject(size * SIZE_IOVEC, false);
|
||||
this.address = vecArray.address();
|
||||
}
|
||||
|
||||
static IOVecWrapper get(int size) {
|
||||
IOVecWrapper wrapper = cached.get();
|
||||
if (wrapper != null && wrapper.size < size) {
|
||||
// not big enough; eagerly release memory
|
||||
wrapper.vecArray.free();
|
||||
wrapper = null;
|
||||
}
|
||||
if (wrapper == null) {
|
||||
wrapper = new IOVecWrapper(size);
|
||||
Cleaner.create(wrapper, new Deallocator(wrapper.vecArray));
|
||||
cached.set(wrapper);
|
||||
}
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
void setBuffer(int i, ByteBuffer buf, int pos, int rem) {
|
||||
this.buf[i] = buf;
|
||||
this.position[i] = pos;
|
||||
this.remaining[i] = rem;
|
||||
}
|
||||
|
||||
void setShadow(int i, ByteBuffer buf) {
|
||||
shadow[i] = buf;
|
||||
}
|
||||
|
||||
ByteBuffer getBuffer(int i) {
|
||||
return buf[i];
|
||||
}
|
||||
|
||||
int getPosition(int i) {
|
||||
return position[i];
|
||||
}
|
||||
|
||||
int getRemaining(int i) {
|
||||
return remaining[i];
|
||||
}
|
||||
|
||||
ByteBuffer getShadow(int i) {
|
||||
return shadow[i];
|
||||
}
|
||||
|
||||
void clearRefs(int i) {
|
||||
buf[i] = null;
|
||||
shadow[i] = null;
|
||||
}
|
||||
|
||||
void putBase(int i, long base) {
|
||||
int offset = SIZE_IOVEC * i + BASE_OFFSET;
|
||||
if (addressSize == 4)
|
||||
vecArray.putInt(offset, (int)base);
|
||||
else
|
||||
vecArray.putLong(offset, base);
|
||||
}
|
||||
|
||||
void putLen(int i, long len) {
|
||||
int offset = SIZE_IOVEC * i + LEN_OFFSET;
|
||||
if (addressSize == 4)
|
||||
vecArray.putInt(offset, (int)len);
|
||||
else
|
||||
vecArray.putLong(offset, len);
|
||||
}
|
||||
|
||||
static {
|
||||
addressSize = Util.unsafe().addressSize();
|
||||
LEN_OFFSET = addressSize;
|
||||
SIZE_IOVEC = (short) (addressSize * 2);
|
||||
}
|
||||
}
|
||||
36
jdkSrc/jdk8/sun/nio/ch/Interruptible.java
Normal file
36
jdkSrc/jdk8/sun/nio/ch/Interruptible.java
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An object that interrupts a thread blocked in an I/O operation.
|
||||
*/
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
public interface Interruptible {
|
||||
|
||||
public void interrupt(Thread t);
|
||||
|
||||
}
|
||||
320
jdkSrc/jdk8/sun/nio/ch/Invoker.java
Normal file
320
jdkSrc/jdk8/sun/nio/ch/Invoker.java
Normal file
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
* 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.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.security.AccessController;
|
||||
import sun.security.action.GetIntegerAction;
|
||||
|
||||
/**
|
||||
* Defines static methods to invoke a completion handler or arbitrary task.
|
||||
*/
|
||||
|
||||
class Invoker {
|
||||
private Invoker() { }
|
||||
|
||||
// maximum number of completion handlers that may be invoked on the current
|
||||
// thread before it re-directs invocations to the thread pool. This helps
|
||||
// avoid stack overflow and lessens the risk of starvation.
|
||||
private static final int maxHandlerInvokeCount = AccessController.doPrivileged(
|
||||
new GetIntegerAction("sun.nio.ch.maxCompletionHandlersOnStack", 16));
|
||||
|
||||
// Per-thread object with reference to channel group and a counter for
|
||||
// the number of completion handlers invoked. This should be reset to 0
|
||||
// when all completion handlers have completed.
|
||||
static class GroupAndInvokeCount {
|
||||
private final AsynchronousChannelGroupImpl group;
|
||||
private int handlerInvokeCount;
|
||||
GroupAndInvokeCount(AsynchronousChannelGroupImpl group) {
|
||||
this.group = group;
|
||||
}
|
||||
AsynchronousChannelGroupImpl group() {
|
||||
return group;
|
||||
}
|
||||
int invokeCount() {
|
||||
return handlerInvokeCount;
|
||||
}
|
||||
void setInvokeCount(int value) {
|
||||
handlerInvokeCount = value;
|
||||
}
|
||||
void resetInvokeCount() {
|
||||
handlerInvokeCount = 0;
|
||||
}
|
||||
void incrementInvokeCount() {
|
||||
handlerInvokeCount++;
|
||||
}
|
||||
}
|
||||
private static final ThreadLocal<GroupAndInvokeCount> myGroupAndInvokeCount =
|
||||
new ThreadLocal<GroupAndInvokeCount>() {
|
||||
@Override protected GroupAndInvokeCount initialValue() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Binds this thread to the given group
|
||||
*/
|
||||
static void bindToGroup(AsynchronousChannelGroupImpl group) {
|
||||
myGroupAndInvokeCount.set(new GroupAndInvokeCount(group));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the GroupAndInvokeCount object for this thread.
|
||||
*/
|
||||
static GroupAndInvokeCount getGroupAndInvokeCount() {
|
||||
return myGroupAndInvokeCount.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current thread is in a channel group's thread pool
|
||||
*/
|
||||
static boolean isBoundToAnyGroup() {
|
||||
return myGroupAndInvokeCount.get() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current thread is in the given channel's thread
|
||||
* pool and we haven't exceeded the maximum number of handler frames on
|
||||
* the stack.
|
||||
*/
|
||||
static boolean mayInvokeDirect(GroupAndInvokeCount myGroupAndInvokeCount,
|
||||
AsynchronousChannelGroupImpl group)
|
||||
{
|
||||
if ((myGroupAndInvokeCount != null) &&
|
||||
(myGroupAndInvokeCount.group() == group) &&
|
||||
(myGroupAndInvokeCount.invokeCount() < maxHandlerInvokeCount))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke handler without checking the thread identity or number of handlers
|
||||
* on the thread stack.
|
||||
*/
|
||||
static <V,A> void invokeUnchecked(CompletionHandler<V,? super A> handler,
|
||||
A attachment,
|
||||
V value,
|
||||
Throwable exc)
|
||||
{
|
||||
if (exc == null) {
|
||||
handler.completed(value, attachment);
|
||||
} else {
|
||||
handler.failed(exc, attachment);
|
||||
}
|
||||
|
||||
// clear interrupt
|
||||
Thread.interrupted();
|
||||
|
||||
// clear thread locals when in default thread pool
|
||||
if (System.getSecurityManager() != null) {
|
||||
Thread me = Thread.currentThread();
|
||||
if (me instanceof sun.misc.InnocuousThread) {
|
||||
GroupAndInvokeCount thisGroupAndInvokeCount = myGroupAndInvokeCount.get();
|
||||
((sun.misc.InnocuousThread)me).eraseThreadLocals();
|
||||
if (thisGroupAndInvokeCount != null) {
|
||||
myGroupAndInvokeCount.set(thisGroupAndInvokeCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke handler assuming thread identity already checked
|
||||
*/
|
||||
static <V,A> void invokeDirect(GroupAndInvokeCount myGroupAndInvokeCount,
|
||||
CompletionHandler<V,? super A> handler,
|
||||
A attachment,
|
||||
V result,
|
||||
Throwable exc)
|
||||
{
|
||||
myGroupAndInvokeCount.incrementInvokeCount();
|
||||
Invoker.invokeUnchecked(handler, attachment, result, exc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the handler. If the current thread is in the channel group's
|
||||
* thread pool then the handler is invoked directly, otherwise it is
|
||||
* invoked indirectly.
|
||||
*/
|
||||
static <V,A> void invoke(AsynchronousChannel channel,
|
||||
CompletionHandler<V,? super A> handler,
|
||||
A attachment,
|
||||
V result,
|
||||
Throwable exc)
|
||||
{
|
||||
boolean invokeDirect = false;
|
||||
boolean identityOkay = false;
|
||||
GroupAndInvokeCount thisGroupAndInvokeCount = myGroupAndInvokeCount.get();
|
||||
if (thisGroupAndInvokeCount != null) {
|
||||
if ((thisGroupAndInvokeCount.group() == ((Groupable)channel).group()))
|
||||
identityOkay = true;
|
||||
if (identityOkay &&
|
||||
(thisGroupAndInvokeCount.invokeCount() < maxHandlerInvokeCount))
|
||||
{
|
||||
// group match
|
||||
invokeDirect = true;
|
||||
}
|
||||
}
|
||||
if (invokeDirect) {
|
||||
invokeDirect(thisGroupAndInvokeCount, handler, attachment, result, exc);
|
||||
} else {
|
||||
try {
|
||||
invokeIndirectly(channel, handler, attachment, result, exc);
|
||||
} catch (RejectedExecutionException ree) {
|
||||
// channel group shutdown; fallback to invoking directly
|
||||
// if the current thread has the right identity.
|
||||
if (identityOkay) {
|
||||
invokeDirect(thisGroupAndInvokeCount,
|
||||
handler, attachment, result, exc);
|
||||
} else {
|
||||
throw new ShutdownChannelGroupException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the handler indirectly via the channel group's thread pool.
|
||||
*/
|
||||
static <V,A> void invokeIndirectly(AsynchronousChannel channel,
|
||||
final CompletionHandler<V,? super A> handler,
|
||||
final A attachment,
|
||||
final V result,
|
||||
final Throwable exc)
|
||||
{
|
||||
try {
|
||||
((Groupable)channel).group().executeOnPooledThread(new Runnable() {
|
||||
public void run() {
|
||||
GroupAndInvokeCount thisGroupAndInvokeCount =
|
||||
myGroupAndInvokeCount.get();
|
||||
if (thisGroupAndInvokeCount != null)
|
||||
thisGroupAndInvokeCount.setInvokeCount(1);
|
||||
invokeUnchecked(handler, attachment, result, exc);
|
||||
}
|
||||
});
|
||||
} catch (RejectedExecutionException ree) {
|
||||
throw new ShutdownChannelGroupException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the handler "indirectly" in the given Executor
|
||||
*/
|
||||
static <V,A> void invokeIndirectly(final CompletionHandler<V,? super A> handler,
|
||||
final A attachment,
|
||||
final V value,
|
||||
final Throwable exc,
|
||||
Executor executor)
|
||||
{
|
||||
try {
|
||||
executor.execute(new Runnable() {
|
||||
public void run() {
|
||||
invokeUnchecked(handler, attachment, value, exc);
|
||||
}
|
||||
});
|
||||
} catch (RejectedExecutionException ree) {
|
||||
throw new ShutdownChannelGroupException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the given task on the thread pool associated with the given
|
||||
* channel. If the current thread is in the thread pool then the task is
|
||||
* invoked directly.
|
||||
*/
|
||||
static void invokeOnThreadInThreadPool(Groupable channel,
|
||||
Runnable task)
|
||||
{
|
||||
boolean invokeDirect;
|
||||
GroupAndInvokeCount thisGroupAndInvokeCount = myGroupAndInvokeCount.get();
|
||||
AsynchronousChannelGroupImpl targetGroup = channel.group();
|
||||
if (thisGroupAndInvokeCount == null) {
|
||||
invokeDirect = false;
|
||||
} else {
|
||||
invokeDirect = (thisGroupAndInvokeCount.group == targetGroup);
|
||||
}
|
||||
try {
|
||||
if (invokeDirect) {
|
||||
task.run();
|
||||
} else {
|
||||
targetGroup.executeOnPooledThread(task);
|
||||
}
|
||||
} catch (RejectedExecutionException ree) {
|
||||
throw new ShutdownChannelGroupException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke handler with completed result. This method does not check the
|
||||
* thread identity or the number of handlers on the thread stack.
|
||||
*/
|
||||
static <V,A> void invokeUnchecked(PendingFuture<V,A> future) {
|
||||
assert future.isDone();
|
||||
CompletionHandler<V,? super A> handler = future.handler();
|
||||
if (handler != null) {
|
||||
invokeUnchecked(handler,
|
||||
future.attachment(),
|
||||
future.value(),
|
||||
future.exception());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke handler with completed result. If the current thread is in the
|
||||
* channel group's thread pool then the handler is invoked directly,
|
||||
* otherwise it is invoked indirectly.
|
||||
*/
|
||||
static <V,A> void invoke(PendingFuture<V,A> future) {
|
||||
assert future.isDone();
|
||||
CompletionHandler<V,? super A> handler = future.handler();
|
||||
if (handler != null) {
|
||||
invoke(future.channel(),
|
||||
handler,
|
||||
future.attachment(),
|
||||
future.value(),
|
||||
future.exception());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke handler with completed result. The handler is invoked indirectly,
|
||||
* via the channel group's thread pool.
|
||||
*/
|
||||
static <V,A> void invokeIndirectly(PendingFuture<V,A> future) {
|
||||
assert future.isDone();
|
||||
CompletionHandler<V,? super A> handler = future.handler();
|
||||
if (handler != null) {
|
||||
invokeIndirectly(future.channel(),
|
||||
handler,
|
||||
future.attachment(),
|
||||
future.value(),
|
||||
future.exception());
|
||||
}
|
||||
}
|
||||
}
|
||||
455
jdkSrc/jdk8/sun/nio/ch/Iocp.java
Normal file
455
jdkSrc/jdk8/sun/nio/ch/Iocp.java
Normal file
@@ -0,0 +1,455 @@
|
||||
/*
|
||||
* 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 java.security.AccessController;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
import sun.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;
|
||||
private static final boolean supportsThreadAgnosticIo;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this operating system supports thread agnostic I/O.
|
||||
*/
|
||||
static boolean supportsThreadAgnosticIo() {
|
||||
return supportsThreadAgnosticIo;
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
||||
// thread agnostic I/O on Vista/2008 or newer
|
||||
String osversion = AccessController.doPrivileged(
|
||||
new GetPropertyAction("os.version"));
|
||||
String vers[] = osversion.split("\\.");
|
||||
supportsThreadAgnosticIo = Integer.parseInt(vers[0]) >= 6;
|
||||
}
|
||||
}
|
||||
220
jdkSrc/jdk8/sun/nio/ch/MembershipKeyImpl.java
Normal file
220
jdkSrc/jdk8/sun/nio/ch/MembershipKeyImpl.java
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* 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.*;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* MembershipKey implementation.
|
||||
*/
|
||||
|
||||
class MembershipKeyImpl
|
||||
extends MembershipKey
|
||||
{
|
||||
private final MulticastChannel ch;
|
||||
private final InetAddress group;
|
||||
private final NetworkInterface interf;
|
||||
private final InetAddress source;
|
||||
|
||||
// true when key is valid
|
||||
private volatile boolean valid = true;
|
||||
|
||||
// lock used when creating or accessing blockedSet
|
||||
private Object stateLock = new Object();
|
||||
|
||||
// set of source addresses that are blocked
|
||||
private HashSet<InetAddress> blockedSet;
|
||||
|
||||
private MembershipKeyImpl(MulticastChannel ch,
|
||||
InetAddress group,
|
||||
NetworkInterface interf,
|
||||
InetAddress source)
|
||||
{
|
||||
this.ch = ch;
|
||||
this.group = group;
|
||||
this.interf = interf;
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
/**
|
||||
* MembershipKey will additional context for IPv4 membership
|
||||
*/
|
||||
static class Type4 extends MembershipKeyImpl {
|
||||
private final int groupAddress;
|
||||
private final int interfAddress;
|
||||
private final int sourceAddress;
|
||||
|
||||
Type4(MulticastChannel ch,
|
||||
InetAddress group,
|
||||
NetworkInterface interf,
|
||||
InetAddress source,
|
||||
int groupAddress,
|
||||
int interfAddress,
|
||||
int sourceAddress)
|
||||
{
|
||||
super(ch, group, interf, source);
|
||||
this.groupAddress = groupAddress;
|
||||
this.interfAddress = interfAddress;
|
||||
this.sourceAddress = sourceAddress;
|
||||
}
|
||||
|
||||
int groupAddress() {
|
||||
return groupAddress;
|
||||
}
|
||||
|
||||
int interfaceAddress() {
|
||||
return interfAddress;
|
||||
}
|
||||
|
||||
int source() {
|
||||
return sourceAddress;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MembershipKey will additional context for IPv6 membership
|
||||
*/
|
||||
static class Type6 extends MembershipKeyImpl {
|
||||
private final byte[] groupAddress;
|
||||
private final int index;
|
||||
private final byte[] sourceAddress;
|
||||
|
||||
Type6(MulticastChannel ch,
|
||||
InetAddress group,
|
||||
NetworkInterface interf,
|
||||
InetAddress source,
|
||||
byte[] groupAddress,
|
||||
int index,
|
||||
byte[] sourceAddress)
|
||||
{
|
||||
super(ch, group, interf, source);
|
||||
this.groupAddress = groupAddress;
|
||||
this.index = index;
|
||||
this.sourceAddress = sourceAddress;
|
||||
}
|
||||
|
||||
byte[] groupAddress() {
|
||||
return groupAddress;
|
||||
}
|
||||
|
||||
int index() {
|
||||
return index;
|
||||
}
|
||||
|
||||
byte[] source() {
|
||||
return sourceAddress;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return valid;
|
||||
}
|
||||
|
||||
// package-private
|
||||
void invalidate() {
|
||||
valid = false;
|
||||
}
|
||||
|
||||
public void drop() {
|
||||
// delegate to channel
|
||||
((DatagramChannelImpl)ch).drop(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MulticastChannel channel() {
|
||||
return ch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetAddress group() {
|
||||
return group;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NetworkInterface networkInterface() {
|
||||
return interf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetAddress sourceAddress() {
|
||||
return source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MembershipKey block(InetAddress toBlock)
|
||||
throws IOException
|
||||
{
|
||||
if (source != null)
|
||||
throw new IllegalStateException("key is source-specific");
|
||||
|
||||
synchronized (stateLock) {
|
||||
if ((blockedSet != null) && blockedSet.contains(toBlock)) {
|
||||
// already blocked, nothing to do
|
||||
return this;
|
||||
}
|
||||
|
||||
((DatagramChannelImpl)ch).block(this, toBlock);
|
||||
|
||||
// created blocked set if required and add source address
|
||||
if (blockedSet == null)
|
||||
blockedSet = new HashSet<InetAddress>();
|
||||
blockedSet.add(toBlock);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MembershipKey unblock(InetAddress toUnblock) {
|
||||
synchronized (stateLock) {
|
||||
if ((blockedSet == null) || !blockedSet.contains(toUnblock))
|
||||
throw new IllegalStateException("not blocked");
|
||||
|
||||
((DatagramChannelImpl)ch).unblock(this, toUnblock);
|
||||
|
||||
blockedSet.remove(toUnblock);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(64);
|
||||
sb.append('<');
|
||||
sb.append(group.getHostAddress());
|
||||
sb.append(',');
|
||||
sb.append(interf.getName());
|
||||
if (source != null) {
|
||||
sb.append(',');
|
||||
sb.append(source.getHostAddress());
|
||||
}
|
||||
sb.append('>');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
131
jdkSrc/jdk8/sun/nio/ch/MembershipRegistry.java
Normal file
131
jdkSrc/jdk8/sun/nio/ch/MembershipRegistry.java
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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.*;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Simple registry of membership keys for a MulticastChannel.
|
||||
*
|
||||
* Instances of this object are not safe by multiple concurrent threads.
|
||||
*/
|
||||
|
||||
class MembershipRegistry {
|
||||
|
||||
// map multicast group to keys
|
||||
private Map<InetAddress,List<MembershipKeyImpl>> groups = null;
|
||||
|
||||
MembershipRegistry() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks registry for membership of the group on the given
|
||||
* network interface.
|
||||
*/
|
||||
MembershipKey checkMembership(InetAddress group, NetworkInterface interf,
|
||||
InetAddress source)
|
||||
{
|
||||
if (groups != null) {
|
||||
List<MembershipKeyImpl> keys = groups.get(group);
|
||||
if (keys != null) {
|
||||
for (MembershipKeyImpl key: keys) {
|
||||
if (key.networkInterface().equals(interf)) {
|
||||
// already a member to receive all packets so return
|
||||
// existing key or detect conflict
|
||||
if (source == null) {
|
||||
if (key.sourceAddress() == null)
|
||||
return key;
|
||||
throw new IllegalStateException("Already a member to receive all packets");
|
||||
}
|
||||
|
||||
// already have source-specific membership so return key
|
||||
// or detect conflict
|
||||
if (key.sourceAddress() == null)
|
||||
throw new IllegalStateException("Already have source-specific membership");
|
||||
if (source.equals(key.sourceAddress()))
|
||||
return key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add membership to the registry, returning a new membership key.
|
||||
*/
|
||||
void add(MembershipKeyImpl key) {
|
||||
InetAddress group = key.group();
|
||||
List<MembershipKeyImpl> keys;
|
||||
if (groups == null) {
|
||||
groups = new HashMap<InetAddress,List<MembershipKeyImpl>>();
|
||||
keys = null;
|
||||
} else {
|
||||
keys = groups.get(group);
|
||||
}
|
||||
if (keys == null) {
|
||||
keys = new LinkedList<MembershipKeyImpl>();
|
||||
groups.put(group, keys);
|
||||
}
|
||||
keys.add(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a key from the registry
|
||||
*/
|
||||
void remove(MembershipKeyImpl key) {
|
||||
InetAddress group = key.group();
|
||||
List<MembershipKeyImpl> keys = groups.get(group);
|
||||
if (keys != null) {
|
||||
Iterator<MembershipKeyImpl> i = keys.iterator();
|
||||
while (i.hasNext()) {
|
||||
if (i.next() == key) {
|
||||
i.remove();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (keys.isEmpty()) {
|
||||
groups.remove(group);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate all keys in the registry
|
||||
*/
|
||||
void invalidateAll() {
|
||||
if (groups != null) {
|
||||
for (InetAddress group: groups.keySet()) {
|
||||
for (MembershipKeyImpl key: groups.get(group)) {
|
||||
key.invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
80
jdkSrc/jdk8/sun/nio/ch/NativeDispatcher.java
Normal file
80
jdkSrc/jdk8/sun/nio/ch/NativeDispatcher.java
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
abstract class NativeDispatcher
|
||||
{
|
||||
|
||||
abstract int read(FileDescriptor fd, long address, int len)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Returns {@code true} if pread/pwrite needs to be synchronized with
|
||||
* position sensitive methods.
|
||||
*/
|
||||
boolean needsPositionLock() {
|
||||
return false;
|
||||
}
|
||||
|
||||
int pread(FileDescriptor fd, long address, int len, long position)
|
||||
throws IOException
|
||||
{
|
||||
throw new IOException("Operation Unsupported");
|
||||
}
|
||||
|
||||
abstract long readv(FileDescriptor fd, long address, int len)
|
||||
throws IOException;
|
||||
|
||||
abstract int write(FileDescriptor fd, long address, int len)
|
||||
throws IOException;
|
||||
|
||||
int pwrite(FileDescriptor fd, long address, int len, long position)
|
||||
throws IOException
|
||||
{
|
||||
throw new IOException("Operation Unsupported");
|
||||
}
|
||||
|
||||
abstract long writev(FileDescriptor fd, long address, int len)
|
||||
throws IOException;
|
||||
|
||||
abstract void close(FileDescriptor fd) throws IOException;
|
||||
|
||||
// Prepare the given fd for closing by duping it to a known internal fd
|
||||
// that's already closed. This is necessary on some operating systems
|
||||
// (Solaris and Linux) to prevent fd recycling.
|
||||
//
|
||||
void preClose(FileDescriptor fd) throws IOException {
|
||||
// Do nothing by default; this is only needed on Unix
|
||||
}
|
||||
|
||||
}
|
||||
405
jdkSrc/jdk8/sun/nio/ch/NativeObject.java
Normal file
405
jdkSrc/jdk8/sun/nio/ch/NativeObject.java
Normal file
@@ -0,0 +1,405 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 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; // Formerly in sun.misc
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
|
||||
// ## In the fullness of time, this class will be eliminated
|
||||
|
||||
/**
|
||||
* Proxies for objects that reside in native memory.
|
||||
*/
|
||||
|
||||
class NativeObject { // package-private
|
||||
|
||||
protected static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||
|
||||
// Native allocation address;
|
||||
// may be smaller than the base address due to page-size rounding
|
||||
//
|
||||
protected long allocationAddress;
|
||||
|
||||
// Native base address
|
||||
//
|
||||
private final long address;
|
||||
|
||||
/**
|
||||
* Creates a new native object that is based at the given native address.
|
||||
*/
|
||||
NativeObject(long address) {
|
||||
this.allocationAddress = address;
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new native object allocated at the given native address but
|
||||
* whose base is at the additional offset.
|
||||
*/
|
||||
NativeObject(long address, long offset) {
|
||||
this.allocationAddress = address;
|
||||
this.address = address + offset;
|
||||
}
|
||||
|
||||
// Invoked only by AllocatedNativeObject
|
||||
//
|
||||
protected NativeObject(int size, boolean pageAligned) {
|
||||
if (!pageAligned) {
|
||||
this.allocationAddress = unsafe.allocateMemory(size);
|
||||
this.address = this.allocationAddress;
|
||||
} else {
|
||||
int ps = pageSize();
|
||||
long a = unsafe.allocateMemory(size + ps);
|
||||
this.allocationAddress = a;
|
||||
this.address = a + ps - (a & (ps - 1));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the native base address of this native object.
|
||||
*
|
||||
* @return The native base address
|
||||
*/
|
||||
long address() {
|
||||
return address;
|
||||
}
|
||||
|
||||
long allocationAddress() {
|
||||
return allocationAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new native object starting at the given offset from the base
|
||||
* of this native object.
|
||||
*
|
||||
* @param offset
|
||||
* The offset from the base of this native object that is to be
|
||||
* the base of the new native object
|
||||
*
|
||||
* @return The newly created native object
|
||||
*/
|
||||
NativeObject subObject(int offset) {
|
||||
return new NativeObject(offset + address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an address from this native object at the given offset and
|
||||
* constructs a native object using that address.
|
||||
*
|
||||
* @param offset
|
||||
* The offset of the address to be read. Note that the size of an
|
||||
* address is implementation-dependent.
|
||||
*
|
||||
* @return The native object created using the address read from the
|
||||
* given offset
|
||||
*/
|
||||
NativeObject getObject(int offset) {
|
||||
long newAddress = 0L;
|
||||
switch (addressSize()) {
|
||||
case 8:
|
||||
newAddress = unsafe.getLong(offset + address);
|
||||
break;
|
||||
case 4:
|
||||
newAddress = unsafe.getInt(offset + address) & 0x00000000FFFFFFFF;
|
||||
break;
|
||||
default:
|
||||
throw new InternalError("Address size not supported");
|
||||
}
|
||||
|
||||
return new NativeObject(newAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the base address of the given native object at the given offset
|
||||
* of this native object.
|
||||
*
|
||||
* @param offset
|
||||
* The offset at which the address is to be written. Note that the
|
||||
* size of an address is implementation-dependent.
|
||||
*
|
||||
* @param ob
|
||||
* The native object whose address is to be written
|
||||
*/
|
||||
void putObject(int offset, NativeObject ob) {
|
||||
switch (addressSize()) {
|
||||
case 8:
|
||||
putLong(offset, ob.address);
|
||||
break;
|
||||
case 4:
|
||||
putInt(offset, (int)(ob.address & 0x00000000FFFFFFFF));
|
||||
break;
|
||||
default:
|
||||
throw new InternalError("Address size not supported");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -- Value accessors: No range checking! -- */
|
||||
|
||||
/**
|
||||
* Reads a byte starting at the given offset from base of this native
|
||||
* object.
|
||||
*
|
||||
* @param offset
|
||||
* The offset at which to read the byte
|
||||
*
|
||||
* @return The byte value read
|
||||
*/
|
||||
final byte getByte(int offset) {
|
||||
return unsafe.getByte(offset + address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a byte at the specified offset from this native object's
|
||||
* base address.
|
||||
*
|
||||
* @param offset
|
||||
* The offset at which to write the byte
|
||||
*
|
||||
* @param value
|
||||
* The byte value to be written
|
||||
*/
|
||||
final void putByte(int offset, byte value) {
|
||||
unsafe.putByte(offset + address, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a short starting at the given offset from base of this native
|
||||
* object.
|
||||
*
|
||||
* @param offset
|
||||
* The offset at which to read the short
|
||||
*
|
||||
* @return The short value read
|
||||
*/
|
||||
final short getShort(int offset) {
|
||||
return unsafe.getShort(offset + address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a short at the specified offset from this native object's
|
||||
* base address.
|
||||
*
|
||||
* @param offset
|
||||
* The offset at which to write the short
|
||||
*
|
||||
* @param value
|
||||
* The short value to be written
|
||||
*/
|
||||
final void putShort(int offset, short value) {
|
||||
unsafe.putShort(offset + address, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a char starting at the given offset from base of this native
|
||||
* object.
|
||||
*
|
||||
* @param offset
|
||||
* The offset at which to read the char
|
||||
*
|
||||
* @return The char value read
|
||||
*/
|
||||
final char getChar(int offset) {
|
||||
return unsafe.getChar(offset + address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a char at the specified offset from this native object's
|
||||
* base address.
|
||||
*
|
||||
* @param offset
|
||||
* The offset at which to write the char
|
||||
*
|
||||
* @param value
|
||||
* The char value to be written
|
||||
*/
|
||||
final void putChar(int offset, char value) {
|
||||
unsafe.putChar(offset + address, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an int starting at the given offset from base of this native
|
||||
* object.
|
||||
*
|
||||
* @param offset
|
||||
* The offset at which to read the int
|
||||
*
|
||||
* @return The int value read
|
||||
*/
|
||||
final int getInt(int offset) {
|
||||
return unsafe.getInt(offset + address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an int at the specified offset from this native object's
|
||||
* base address.
|
||||
*
|
||||
* @param offset
|
||||
* The offset at which to write the int
|
||||
*
|
||||
* @param value
|
||||
* The int value to be written
|
||||
*/
|
||||
final void putInt(int offset, int value) {
|
||||
unsafe.putInt(offset + address, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a long starting at the given offset from base of this native
|
||||
* object.
|
||||
*
|
||||
* @param offset
|
||||
* The offset at which to read the long
|
||||
*
|
||||
* @return The long value read
|
||||
*/
|
||||
final long getLong(int offset) {
|
||||
return unsafe.getLong(offset + address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a long at the specified offset from this native object's
|
||||
* base address.
|
||||
*
|
||||
* @param offset
|
||||
* The offset at which to write the long
|
||||
*
|
||||
* @param value
|
||||
* The long value to be written
|
||||
*/
|
||||
final void putLong(int offset, long value) {
|
||||
unsafe.putLong(offset + address, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a float starting at the given offset from base of this native
|
||||
* object.
|
||||
*
|
||||
* @param offset
|
||||
* The offset at which to read the float
|
||||
*
|
||||
* @return The float value read
|
||||
*/
|
||||
final float getFloat(int offset) {
|
||||
return unsafe.getFloat(offset + address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a float at the specified offset from this native object's
|
||||
* base address.
|
||||
*
|
||||
* @param offset
|
||||
* The offset at which to write the float
|
||||
*
|
||||
* @param value
|
||||
* The float value to be written
|
||||
*/
|
||||
final void putFloat(int offset, float value) {
|
||||
unsafe.putFloat(offset + address, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a double starting at the given offset from base of this native
|
||||
* object.
|
||||
*
|
||||
* @param offset
|
||||
* The offset at which to read the double
|
||||
*
|
||||
* @return The double value read
|
||||
*/
|
||||
final double getDouble(int offset) {
|
||||
return unsafe.getDouble(offset + address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a double at the specified offset from this native object's
|
||||
* base address.
|
||||
*
|
||||
* @param offset
|
||||
* The offset at which to write the double
|
||||
*
|
||||
* @param value
|
||||
* The double value to be written
|
||||
*/
|
||||
final void putDouble(int offset, double value) {
|
||||
unsafe.putDouble(offset + address, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the native architecture's address size in bytes.
|
||||
*
|
||||
* @return The address size of the native architecture
|
||||
*/
|
||||
static int addressSize() {
|
||||
return unsafe.addressSize();
|
||||
}
|
||||
|
||||
// Cache for byte order
|
||||
private static ByteOrder byteOrder = null;
|
||||
|
||||
/**
|
||||
* Returns the byte order of the underlying hardware.
|
||||
*
|
||||
* @return An instance of {@link java.nio.ByteOrder}
|
||||
*/
|
||||
static ByteOrder byteOrder() {
|
||||
if (byteOrder != null)
|
||||
return byteOrder;
|
||||
long a = unsafe.allocateMemory(8);
|
||||
try {
|
||||
unsafe.putLong(a, 0x0102030405060708L);
|
||||
byte b = unsafe.getByte(a);
|
||||
switch (b) {
|
||||
case 0x01: byteOrder = ByteOrder.BIG_ENDIAN; break;
|
||||
case 0x08: byteOrder = ByteOrder.LITTLE_ENDIAN; break;
|
||||
default:
|
||||
assert false;
|
||||
}
|
||||
} finally {
|
||||
unsafe.freeMemory(a);
|
||||
}
|
||||
return byteOrder;
|
||||
}
|
||||
|
||||
// Cache for page size
|
||||
private static int pageSize = -1;
|
||||
|
||||
/**
|
||||
* Returns the page size of the underlying hardware.
|
||||
*
|
||||
* @return The page size, in bytes
|
||||
*/
|
||||
static int pageSize() {
|
||||
if (pageSize == -1)
|
||||
pageSize = unsafe.pageSize();
|
||||
return pageSize;
|
||||
}
|
||||
|
||||
}
|
||||
42
jdkSrc/jdk8/sun/nio/ch/NativeThread.java
Normal file
42
jdkSrc/jdk8/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) { }
|
||||
|
||||
}
|
||||
111
jdkSrc/jdk8/sun/nio/ch/NativeThreadSet.java
Normal file
111
jdkSrc/jdk8/sun/nio/ch/NativeThreadSet.java
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
|
||||
// Special-purpose data structure for sets of native threads
|
||||
|
||||
|
||||
class NativeThreadSet {
|
||||
|
||||
private long[] elts;
|
||||
private int used = 0;
|
||||
private boolean waitingToEmpty;
|
||||
|
||||
NativeThreadSet(int n) {
|
||||
elts = new long[n];
|
||||
}
|
||||
|
||||
// Adds the current native thread to this set, returning its index so that
|
||||
// it can efficiently be removed later.
|
||||
//
|
||||
int add() {
|
||||
long th = NativeThread.current();
|
||||
// 0 and -1 are treated as placeholders, not real thread handles
|
||||
if (th == 0)
|
||||
th = -1;
|
||||
synchronized (this) {
|
||||
int start = 0;
|
||||
if (used >= elts.length) {
|
||||
int on = elts.length;
|
||||
int nn = on * 2;
|
||||
long[] nelts = new long[nn];
|
||||
System.arraycopy(elts, 0, nelts, 0, on);
|
||||
elts = nelts;
|
||||
start = on;
|
||||
}
|
||||
for (int i = start; i < elts.length; i++) {
|
||||
if (elts[i] == 0) {
|
||||
elts[i] = th;
|
||||
used++;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
assert false;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Removes the thread at the given index.
|
||||
//
|
||||
void remove(int i) {
|
||||
synchronized (this) {
|
||||
elts[i] = 0;
|
||||
used--;
|
||||
if (used == 0 && waitingToEmpty)
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
// Signals all threads in this set.
|
||||
//
|
||||
synchronized void signalAndWait() {
|
||||
boolean interrupted = false;
|
||||
while (used > 0) {
|
||||
int u = used;
|
||||
int n = elts.length;
|
||||
for (int i = 0; i < n; i++) {
|
||||
long th = elts[i];
|
||||
if (th == 0)
|
||||
continue;
|
||||
if (th != -1)
|
||||
NativeThread.signal(th);
|
||||
if (--u == 0)
|
||||
break;
|
||||
}
|
||||
waitingToEmpty = true;
|
||||
try {
|
||||
wait(50);
|
||||
} catch (InterruptedException e) {
|
||||
interrupted = true;
|
||||
} finally {
|
||||
waitingToEmpty = false;
|
||||
}
|
||||
}
|
||||
if (interrupted)
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
687
jdkSrc/jdk8/sun/nio/ch/Net.java
Normal file
687
jdkSrc/jdk8/sun/nio/ch/Net.java
Normal file
@@ -0,0 +1,687 @@
|
||||
/*
|
||||
* 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.*;
|
||||
import java.net.*;
|
||||
import jdk.net.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.*;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import sun.net.ExtendedOptionsImpl;
|
||||
import static jdk.net.ExtendedSocketOptions.TCP_KEEPCOUNT;
|
||||
import static jdk.net.ExtendedSocketOptions.TCP_KEEPIDLE;
|
||||
import static jdk.net.ExtendedSocketOptions.TCP_KEEPINTERVAL;
|
||||
|
||||
|
||||
public class Net {
|
||||
|
||||
private Net() { }
|
||||
|
||||
// unspecified protocol family
|
||||
static final ProtocolFamily UNSPEC = new ProtocolFamily() {
|
||||
public String name() {
|
||||
return "UNSPEC";
|
||||
}
|
||||
};
|
||||
|
||||
// set to true if exclusive binding is on for Windows
|
||||
private static final boolean exclusiveBind;
|
||||
|
||||
// set to true if the fast tcp loopback should be enabled on Windows
|
||||
private static final boolean fastLoopback;
|
||||
|
||||
// -- Miscellaneous utilities --
|
||||
|
||||
private static volatile boolean checkedIPv6 = false;
|
||||
private static volatile boolean isIPv6Available;
|
||||
|
||||
/**
|
||||
* Tells whether dual-IPv4/IPv6 sockets should be used.
|
||||
*/
|
||||
static boolean isIPv6Available() {
|
||||
if (!checkedIPv6) {
|
||||
isIPv6Available = isIPv6Available0();
|
||||
checkedIPv6 = true;
|
||||
}
|
||||
return isIPv6Available;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if exclusive binding is on
|
||||
*/
|
||||
static boolean useExclusiveBind() {
|
||||
return exclusiveBind;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether IPv6 sockets can join IPv4 multicast groups
|
||||
*/
|
||||
static boolean canIPv6SocketJoinIPv4Group() {
|
||||
return canIPv6SocketJoinIPv4Group0();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether {@link #join6} can be used to join an IPv4
|
||||
* multicast group (IPv4 group as IPv4-mapped IPv6 address)
|
||||
*/
|
||||
static boolean canJoin6WithIPv4Group() {
|
||||
return canJoin6WithIPv4Group0();
|
||||
}
|
||||
|
||||
public static InetSocketAddress checkAddress(SocketAddress sa) {
|
||||
if (sa == null)
|
||||
throw new NullPointerException();
|
||||
if (!(sa instanceof InetSocketAddress))
|
||||
throw new UnsupportedAddressTypeException(); // ## needs arg
|
||||
InetSocketAddress isa = (InetSocketAddress)sa;
|
||||
if (isa.isUnresolved())
|
||||
throw new UnresolvedAddressException(); // ## needs arg
|
||||
InetAddress addr = isa.getAddress();
|
||||
if (!(addr instanceof Inet4Address || addr instanceof Inet6Address))
|
||||
throw new IllegalArgumentException("Invalid address type");
|
||||
return isa;
|
||||
}
|
||||
|
||||
static InetSocketAddress asInetSocketAddress(SocketAddress sa) {
|
||||
if (!(sa instanceof InetSocketAddress))
|
||||
throw new UnsupportedAddressTypeException();
|
||||
return (InetSocketAddress)sa;
|
||||
}
|
||||
|
||||
static void translateToSocketException(Exception x)
|
||||
throws SocketException
|
||||
{
|
||||
if (x instanceof SocketException)
|
||||
throw (SocketException)x;
|
||||
Exception nx = x;
|
||||
if (x instanceof ClosedChannelException)
|
||||
nx = new SocketException("Socket is closed");
|
||||
else if (x instanceof NotYetConnectedException)
|
||||
nx = new SocketException("Socket is not connected");
|
||||
else if (x instanceof AlreadyBoundException)
|
||||
nx = new SocketException("Already bound");
|
||||
else if (x instanceof NotYetBoundException)
|
||||
nx = new SocketException("Socket is not bound yet");
|
||||
else if (x instanceof UnsupportedAddressTypeException)
|
||||
nx = new SocketException("Unsupported address type");
|
||||
else if (x instanceof UnresolvedAddressException) {
|
||||
nx = new SocketException("Unresolved address");
|
||||
}
|
||||
if (nx != x)
|
||||
nx.initCause(x);
|
||||
|
||||
if (nx instanceof SocketException)
|
||||
throw (SocketException)nx;
|
||||
else if (nx instanceof RuntimeException)
|
||||
throw (RuntimeException)nx;
|
||||
else
|
||||
throw new Error("Untranslated exception", nx);
|
||||
}
|
||||
|
||||
static void translateException(Exception x,
|
||||
boolean unknownHostForUnresolved)
|
||||
throws IOException
|
||||
{
|
||||
if (x instanceof IOException)
|
||||
throw (IOException)x;
|
||||
// Throw UnknownHostException from here since it cannot
|
||||
// be thrown as a SocketException
|
||||
if (unknownHostForUnresolved &&
|
||||
(x instanceof UnresolvedAddressException))
|
||||
{
|
||||
throw new UnknownHostException();
|
||||
}
|
||||
translateToSocketException(x);
|
||||
}
|
||||
|
||||
static void translateException(Exception x)
|
||||
throws IOException
|
||||
{
|
||||
translateException(x, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the local address after performing a SecurityManager#checkConnect.
|
||||
*/
|
||||
static InetSocketAddress getRevealedLocalAddress(InetSocketAddress addr) {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (addr == null || sm == null)
|
||||
return addr;
|
||||
|
||||
try{
|
||||
sm.checkConnect(addr.getAddress().getHostAddress(), -1);
|
||||
// Security check passed
|
||||
} catch (SecurityException e) {
|
||||
// Return loopback address only if security check fails
|
||||
addr = getLoopbackAddress(addr.getPort());
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
static String getRevealedLocalAddressAsString(InetSocketAddress addr) {
|
||||
return System.getSecurityManager() == null ? addr.toString() :
|
||||
getLoopbackAddress(addr.getPort()).toString();
|
||||
}
|
||||
|
||||
private static InetSocketAddress getLoopbackAddress(int port) {
|
||||
return new InetSocketAddress(InetAddress.getLoopbackAddress(),
|
||||
port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns any IPv4 address of the given network interface, or
|
||||
* null if the interface does not have any IPv4 addresses.
|
||||
*/
|
||||
static Inet4Address anyInet4Address(final NetworkInterface interf) {
|
||||
return AccessController.doPrivileged(new PrivilegedAction<Inet4Address>() {
|
||||
public Inet4Address run() {
|
||||
Enumeration<InetAddress> addrs = interf.getInetAddresses();
|
||||
while (addrs.hasMoreElements()) {
|
||||
InetAddress addr = addrs.nextElement();
|
||||
if (addr instanceof Inet4Address) {
|
||||
return (Inet4Address)addr;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an IPv4 address as an int.
|
||||
*/
|
||||
static int inet4AsInt(InetAddress ia) {
|
||||
if (ia instanceof Inet4Address) {
|
||||
byte[] addr = ia.getAddress();
|
||||
int address = addr[3] & 0xFF;
|
||||
address |= ((addr[2] << 8) & 0xFF00);
|
||||
address |= ((addr[1] << 16) & 0xFF0000);
|
||||
address |= ((addr[0] << 24) & 0xFF000000);
|
||||
return address;
|
||||
}
|
||||
throw new AssertionError("Should not reach here");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an InetAddress from the given IPv4 address
|
||||
* represented as an int.
|
||||
*/
|
||||
static InetAddress inet4FromInt(int address) {
|
||||
byte[] addr = new byte[4];
|
||||
addr[0] = (byte) ((address >>> 24) & 0xFF);
|
||||
addr[1] = (byte) ((address >>> 16) & 0xFF);
|
||||
addr[2] = (byte) ((address >>> 8) & 0xFF);
|
||||
addr[3] = (byte) (address & 0xFF);
|
||||
try {
|
||||
return InetAddress.getByAddress(addr);
|
||||
} catch (UnknownHostException uhe) {
|
||||
throw new AssertionError("Should not reach here");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an IPv6 address as a byte array
|
||||
*/
|
||||
static byte[] inet6AsByteArray(InetAddress ia) {
|
||||
if (ia instanceof Inet6Address) {
|
||||
return ia.getAddress();
|
||||
}
|
||||
|
||||
// need to construct IPv4-mapped address
|
||||
if (ia instanceof Inet4Address) {
|
||||
byte[] ip4address = ia.getAddress();
|
||||
byte[] address = new byte[16];
|
||||
address[10] = (byte)0xff;
|
||||
address[11] = (byte)0xff;
|
||||
address[12] = ip4address[0];
|
||||
address[13] = ip4address[1];
|
||||
address[14] = ip4address[2];
|
||||
address[15] = ip4address[3];
|
||||
return address;
|
||||
}
|
||||
|
||||
throw new AssertionError("Should not reach here");
|
||||
}
|
||||
|
||||
// -- Socket options
|
||||
|
||||
static void setSocketOption(FileDescriptor fd, ProtocolFamily family,
|
||||
SocketOption<?> name, Object value)
|
||||
throws IOException
|
||||
{
|
||||
if (value == null)
|
||||
throw new IllegalArgumentException("Invalid option value");
|
||||
|
||||
// only simple values supported by this method
|
||||
Class<?> type = name.type();
|
||||
|
||||
if (type == SocketFlow.class) {
|
||||
ExtendedOptionsImpl.checkSetOptionPermission(name);
|
||||
ExtendedOptionsImpl.checkValueType(value, SocketFlow.class);
|
||||
ExtendedOptionsImpl.setFlowOption(fd, (SocketFlow)value);
|
||||
return;
|
||||
}
|
||||
if (name == TCP_KEEPINTERVAL) {
|
||||
ExtendedOptionsImpl.checkSetOptionPermission(name);
|
||||
ExtendedOptionsImpl.checkValueType(value, Integer.class);
|
||||
ExtendedOptionsImpl.setTcpKeepAliveIntvl(fd, (Integer)value);
|
||||
return;
|
||||
}
|
||||
if (name == TCP_KEEPIDLE) {
|
||||
ExtendedOptionsImpl.checkSetOptionPermission(name);
|
||||
ExtendedOptionsImpl.checkValueType(value, Integer.class);
|
||||
ExtendedOptionsImpl.setTcpKeepAliveTime(fd, (Integer)value);
|
||||
return;
|
||||
}
|
||||
if (name == TCP_KEEPCOUNT) {
|
||||
ExtendedOptionsImpl.checkSetOptionPermission(name);
|
||||
ExtendedOptionsImpl.checkValueType(value, Integer.class);
|
||||
ExtendedOptionsImpl.setTcpKeepAliveProbes(fd, (Integer)value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type != Integer.class && type != Boolean.class)
|
||||
throw new AssertionError("Should not reach here");
|
||||
|
||||
// special handling
|
||||
if (name == StandardSocketOptions.SO_RCVBUF ||
|
||||
name == StandardSocketOptions.SO_SNDBUF)
|
||||
{
|
||||
int i = ((Integer)value).intValue();
|
||||
if (i < 0)
|
||||
throw new IllegalArgumentException("Invalid send/receive buffer size");
|
||||
}
|
||||
if (name == StandardSocketOptions.SO_LINGER) {
|
||||
int i = ((Integer)value).intValue();
|
||||
if (i < 0)
|
||||
value = Integer.valueOf(-1);
|
||||
if (i > 65535)
|
||||
value = Integer.valueOf(65535);
|
||||
}
|
||||
if (name == StandardSocketOptions.IP_TOS) {
|
||||
int i = ((Integer)value).intValue();
|
||||
if (i < 0 || i > 255)
|
||||
throw new IllegalArgumentException("Invalid IP_TOS value");
|
||||
}
|
||||
if (name == StandardSocketOptions.IP_MULTICAST_TTL) {
|
||||
int i = ((Integer)value).intValue();
|
||||
if (i < 0 || i > 255)
|
||||
throw new IllegalArgumentException("Invalid TTL/hop value");
|
||||
}
|
||||
|
||||
// map option name to platform level/name
|
||||
OptionKey key = SocketOptionRegistry.findOption(name, family);
|
||||
if (key == null)
|
||||
throw new AssertionError("Option not found");
|
||||
|
||||
int arg;
|
||||
if (type == Integer.class) {
|
||||
arg = ((Integer)value).intValue();
|
||||
} else {
|
||||
boolean b = ((Boolean)value).booleanValue();
|
||||
arg = (b) ? 1 : 0;
|
||||
}
|
||||
|
||||
boolean mayNeedConversion = (family == UNSPEC);
|
||||
boolean isIPv6 = (family == StandardProtocolFamily.INET6);
|
||||
setIntOption0(fd, mayNeedConversion, key.level(), key.name(), arg, isIPv6);
|
||||
}
|
||||
|
||||
static Object getSocketOption(FileDescriptor fd, ProtocolFamily family,
|
||||
SocketOption<?> name)
|
||||
throws IOException
|
||||
{
|
||||
Class<?> type = name.type();
|
||||
|
||||
if (type == SocketFlow.class) {
|
||||
ExtendedOptionsImpl.checkGetOptionPermission(name);
|
||||
SocketFlow flow = SocketFlow.create();
|
||||
ExtendedOptionsImpl.getFlowOption(fd, flow);
|
||||
return flow;
|
||||
}
|
||||
if (name == TCP_KEEPINTERVAL) {
|
||||
ExtendedOptionsImpl.checkGetOptionPermission(name);
|
||||
return ExtendedOptionsImpl.getTcpKeepAliveIntvl(fd);
|
||||
}
|
||||
if (name == TCP_KEEPIDLE) {
|
||||
ExtendedOptionsImpl.checkGetOptionPermission(name);
|
||||
return ExtendedOptionsImpl.getTcpKeepAliveTime(fd);
|
||||
}
|
||||
if (name == TCP_KEEPCOUNT) {
|
||||
ExtendedOptionsImpl.checkGetOptionPermission(name);
|
||||
return ExtendedOptionsImpl.getTcpKeepAliveProbes(fd);
|
||||
}
|
||||
|
||||
// only simple values supported by this method
|
||||
if (type != Integer.class && type != Boolean.class)
|
||||
throw new AssertionError("Should not reach here");
|
||||
|
||||
// map option name to platform level/name
|
||||
OptionKey key = SocketOptionRegistry.findOption(name, family);
|
||||
if (key == null)
|
||||
throw new AssertionError("Option not found");
|
||||
|
||||
boolean mayNeedConversion = (family == UNSPEC);
|
||||
int value = getIntOption0(fd, mayNeedConversion, key.level(), key.name());
|
||||
|
||||
if (type == Integer.class) {
|
||||
return Integer.valueOf(value);
|
||||
} else {
|
||||
return (value == 0) ? Boolean.FALSE : Boolean.TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isFastTcpLoopbackRequested() {
|
||||
String loopbackProp = java.security.AccessController.doPrivileged(
|
||||
new PrivilegedAction<String>() {
|
||||
@Override
|
||||
public String run() {
|
||||
return System.getProperty("jdk.net.useFastTcpLoopback");
|
||||
}
|
||||
});
|
||||
boolean enable;
|
||||
if ("".equals(loopbackProp)) {
|
||||
enable = true;
|
||||
} else {
|
||||
enable = Boolean.parseBoolean(loopbackProp);
|
||||
}
|
||||
return enable;
|
||||
}
|
||||
|
||||
// -- Socket operations --
|
||||
|
||||
private static native boolean isIPv6Available0();
|
||||
|
||||
/*
|
||||
* Returns 1 for Windows versions that support exclusive binding by default, 0
|
||||
* for those that do not, and -1 for Solaris/Linux/Mac OS
|
||||
*/
|
||||
private static native int isExclusiveBindAvailable();
|
||||
|
||||
private static native boolean canIPv6SocketJoinIPv4Group0();
|
||||
|
||||
private static native boolean canJoin6WithIPv4Group0();
|
||||
|
||||
static FileDescriptor socket(boolean stream) throws IOException {
|
||||
return socket(UNSPEC, stream);
|
||||
}
|
||||
|
||||
static FileDescriptor socket(ProtocolFamily family, boolean stream)
|
||||
throws IOException {
|
||||
boolean preferIPv6 = isIPv6Available() &&
|
||||
(family != StandardProtocolFamily.INET);
|
||||
return IOUtil.newFD(socket0(preferIPv6, stream, false, fastLoopback));
|
||||
}
|
||||
|
||||
static FileDescriptor serverSocket(boolean stream) {
|
||||
return IOUtil.newFD(socket0(isIPv6Available(), stream, true, fastLoopback));
|
||||
}
|
||||
|
||||
// Due to oddities SO_REUSEADDR on windows reuse is ignored
|
||||
private static native int socket0(boolean preferIPv6, boolean stream, boolean reuse,
|
||||
boolean fastLoopback);
|
||||
|
||||
public static void bind(FileDescriptor fd, InetAddress addr, int port)
|
||||
throws IOException
|
||||
{
|
||||
bind(UNSPEC, fd, addr, port);
|
||||
}
|
||||
|
||||
static void bind(ProtocolFamily family, FileDescriptor fd,
|
||||
InetAddress addr, int port) throws IOException
|
||||
{
|
||||
boolean preferIPv6 = isIPv6Available() &&
|
||||
(family != StandardProtocolFamily.INET);
|
||||
bind0(fd, preferIPv6, exclusiveBind, addr, port);
|
||||
}
|
||||
|
||||
private static native void bind0(FileDescriptor fd, boolean preferIPv6,
|
||||
boolean useExclBind, InetAddress addr,
|
||||
int port)
|
||||
throws IOException;
|
||||
|
||||
static native void listen(FileDescriptor fd, int backlog) throws IOException;
|
||||
|
||||
static int connect(FileDescriptor fd, InetAddress remote, int remotePort)
|
||||
throws IOException
|
||||
{
|
||||
return connect(UNSPEC, fd, remote, remotePort);
|
||||
}
|
||||
|
||||
static int connect(ProtocolFamily family, FileDescriptor fd, InetAddress remote, int remotePort)
|
||||
throws IOException
|
||||
{
|
||||
boolean preferIPv6 = isIPv6Available() &&
|
||||
(family != StandardProtocolFamily.INET);
|
||||
return connect0(preferIPv6, fd, remote, remotePort);
|
||||
}
|
||||
|
||||
private static native int connect0(boolean preferIPv6,
|
||||
FileDescriptor fd,
|
||||
InetAddress remote,
|
||||
int remotePort)
|
||||
throws IOException;
|
||||
|
||||
|
||||
public final static int SHUT_RD = 0;
|
||||
public final static int SHUT_WR = 1;
|
||||
public final static int SHUT_RDWR = 2;
|
||||
|
||||
static native void shutdown(FileDescriptor fd, int how) throws IOException;
|
||||
|
||||
private static native int localPort(FileDescriptor fd)
|
||||
throws IOException;
|
||||
|
||||
private static native InetAddress localInetAddress(FileDescriptor fd)
|
||||
throws IOException;
|
||||
|
||||
public static InetSocketAddress localAddress(FileDescriptor fd)
|
||||
throws IOException
|
||||
{
|
||||
return new InetSocketAddress(localInetAddress(fd), localPort(fd));
|
||||
}
|
||||
|
||||
private static native int remotePort(FileDescriptor fd)
|
||||
throws IOException;
|
||||
|
||||
private static native InetAddress remoteInetAddress(FileDescriptor fd)
|
||||
throws IOException;
|
||||
|
||||
static InetSocketAddress remoteAddress(FileDescriptor fd)
|
||||
throws IOException
|
||||
{
|
||||
return new InetSocketAddress(remoteInetAddress(fd), remotePort(fd));
|
||||
}
|
||||
|
||||
private static native int getIntOption0(FileDescriptor fd, boolean mayNeedConversion,
|
||||
int level, int opt)
|
||||
throws IOException;
|
||||
|
||||
private static native void setIntOption0(FileDescriptor fd, boolean mayNeedConversion,
|
||||
int level, int opt, int arg, boolean isIPv6)
|
||||
throws IOException;
|
||||
|
||||
static native int poll(FileDescriptor fd, int events, long timeout)
|
||||
throws IOException;
|
||||
|
||||
// -- Multicast support --
|
||||
|
||||
|
||||
/**
|
||||
* Join IPv4 multicast group
|
||||
*/
|
||||
static int join4(FileDescriptor fd, int group, int interf, int source)
|
||||
throws IOException
|
||||
{
|
||||
return joinOrDrop4(true, fd, group, interf, source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop membership of IPv4 multicast group
|
||||
*/
|
||||
static void drop4(FileDescriptor fd, int group, int interf, int source)
|
||||
throws IOException
|
||||
{
|
||||
joinOrDrop4(false, fd, group, interf, source);
|
||||
}
|
||||
|
||||
private static native int joinOrDrop4(boolean join, FileDescriptor fd, int group, int interf, int source)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Block IPv4 source
|
||||
*/
|
||||
static int block4(FileDescriptor fd, int group, int interf, int source)
|
||||
throws IOException
|
||||
{
|
||||
return blockOrUnblock4(true, fd, group, interf, source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unblock IPv6 source
|
||||
*/
|
||||
static void unblock4(FileDescriptor fd, int group, int interf, int source)
|
||||
throws IOException
|
||||
{
|
||||
blockOrUnblock4(false, fd, group, interf, source);
|
||||
}
|
||||
|
||||
private static native int blockOrUnblock4(boolean block, FileDescriptor fd, int group,
|
||||
int interf, int source)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Join IPv6 multicast group
|
||||
*/
|
||||
static int join6(FileDescriptor fd, byte[] group, int index, byte[] source)
|
||||
throws IOException
|
||||
{
|
||||
return joinOrDrop6(true, fd, group, index, source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop membership of IPv6 multicast group
|
||||
*/
|
||||
static void drop6(FileDescriptor fd, byte[] group, int index, byte[] source)
|
||||
throws IOException
|
||||
{
|
||||
joinOrDrop6(false, fd, group, index, source);
|
||||
}
|
||||
|
||||
private static native int joinOrDrop6(boolean join, FileDescriptor fd, byte[] group, int index, byte[] source)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Block IPv6 source
|
||||
*/
|
||||
static int block6(FileDescriptor fd, byte[] group, int index, byte[] source)
|
||||
throws IOException
|
||||
{
|
||||
return blockOrUnblock6(true, fd, group, index, source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unblock IPv6 source
|
||||
*/
|
||||
static void unblock6(FileDescriptor fd, byte[] group, int index, byte[] source)
|
||||
throws IOException
|
||||
{
|
||||
blockOrUnblock6(false, fd, group, index, source);
|
||||
}
|
||||
|
||||
static native int blockOrUnblock6(boolean block, FileDescriptor fd, byte[] group, int index, byte[] source)
|
||||
throws IOException;
|
||||
|
||||
static native void setInterface4(FileDescriptor fd, int interf) throws IOException;
|
||||
|
||||
static native int getInterface4(FileDescriptor fd) throws IOException;
|
||||
|
||||
static native void setInterface6(FileDescriptor fd, int index) throws IOException;
|
||||
|
||||
static native int getInterface6(FileDescriptor fd) throws IOException;
|
||||
|
||||
private static native void initIDs();
|
||||
|
||||
/**
|
||||
* Event masks for the various poll system calls.
|
||||
* They will be set platform dependant in the static initializer below.
|
||||
*/
|
||||
public static final short POLLIN;
|
||||
public static final short POLLOUT;
|
||||
public static final short POLLERR;
|
||||
public static final short POLLHUP;
|
||||
public static final short POLLNVAL;
|
||||
public static final short POLLCONN;
|
||||
|
||||
static native short pollinValue();
|
||||
static native short polloutValue();
|
||||
static native short pollerrValue();
|
||||
static native short pollhupValue();
|
||||
static native short pollnvalValue();
|
||||
static native short pollconnValue();
|
||||
|
||||
static {
|
||||
IOUtil.load();
|
||||
initIDs();
|
||||
|
||||
POLLIN = pollinValue();
|
||||
POLLOUT = polloutValue();
|
||||
POLLERR = pollerrValue();
|
||||
POLLHUP = pollhupValue();
|
||||
POLLNVAL = pollnvalValue();
|
||||
POLLCONN = pollconnValue();
|
||||
}
|
||||
|
||||
static {
|
||||
int availLevel = isExclusiveBindAvailable();
|
||||
if (availLevel >= 0) {
|
||||
String exclBindProp =
|
||||
java.security.AccessController.doPrivileged(
|
||||
new PrivilegedAction<String>() {
|
||||
@Override
|
||||
public String run() {
|
||||
return System.getProperty(
|
||||
"sun.net.useExclusiveBind");
|
||||
}
|
||||
});
|
||||
if (exclBindProp != null) {
|
||||
exclusiveBind = exclBindProp.length() == 0 ?
|
||||
true : Boolean.parseBoolean(exclBindProp);
|
||||
} else if (availLevel == 1) {
|
||||
exclusiveBind = true;
|
||||
} else {
|
||||
exclusiveBind = false;
|
||||
}
|
||||
} else {
|
||||
exclusiveBind = false;
|
||||
}
|
||||
|
||||
fastLoopback = isFastTcpLoopbackRequested();
|
||||
}
|
||||
}
|
||||
48
jdkSrc/jdk8/sun/nio/ch/OptionKey.java
Normal file
48
jdkSrc/jdk8/sun/nio/ch/OptionKey.java
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 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;
|
||||
|
||||
/**
|
||||
* Represents the level/name of a socket option
|
||||
*/
|
||||
|
||||
class OptionKey {
|
||||
private int level;
|
||||
private int name;
|
||||
|
||||
OptionKey(int level, int name) {
|
||||
this.level = level;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
int level() {
|
||||
return level;
|
||||
}
|
||||
|
||||
int name() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
254
jdkSrc/jdk8/sun/nio/ch/PendingFuture.java
Normal file
254
jdkSrc/jdk8/sun/nio/ch/PendingFuture.java
Normal file
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* 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.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A Future for a pending I/O operation. A PendingFuture allows for the
|
||||
* attachment of an additional arbitrary context object and a timer task.
|
||||
*/
|
||||
|
||||
final class PendingFuture<V,A> implements Future<V> {
|
||||
private static final CancellationException CANCELLED =
|
||||
new CancellationException();
|
||||
|
||||
private final AsynchronousChannel channel;
|
||||
private final CompletionHandler<V,? super A> handler;
|
||||
private final A attachment;
|
||||
|
||||
// true if result (or exception) is available
|
||||
private volatile boolean haveResult;
|
||||
private volatile V result;
|
||||
private volatile Throwable exc;
|
||||
|
||||
// latch for waiting (created lazily if needed)
|
||||
private CountDownLatch latch;
|
||||
|
||||
// optional timer task that is cancelled when result becomes available
|
||||
private Future<?> timeoutTask;
|
||||
|
||||
// optional context object
|
||||
private volatile Object context;
|
||||
|
||||
PendingFuture(AsynchronousChannel channel,
|
||||
CompletionHandler<V,? super A> handler,
|
||||
A attachment,
|
||||
Object context)
|
||||
{
|
||||
this.channel = channel;
|
||||
this.handler = handler;
|
||||
this.attachment = attachment;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
PendingFuture(AsynchronousChannel channel,
|
||||
CompletionHandler<V,? super A> handler,
|
||||
A attachment)
|
||||
{
|
||||
this.channel = channel;
|
||||
this.handler = handler;
|
||||
this.attachment = attachment;
|
||||
}
|
||||
|
||||
PendingFuture(AsynchronousChannel channel) {
|
||||
this(channel, null, null);
|
||||
}
|
||||
|
||||
PendingFuture(AsynchronousChannel channel, Object context) {
|
||||
this(channel, null, null, context);
|
||||
}
|
||||
|
||||
AsynchronousChannel channel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
CompletionHandler<V,? super A> handler() {
|
||||
return handler;
|
||||
}
|
||||
|
||||
A attachment() {
|
||||
return attachment;
|
||||
}
|
||||
|
||||
void setContext(Object context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
Object getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
void setTimeoutTask(Future<?> task) {
|
||||
synchronized (this) {
|
||||
if (haveResult) {
|
||||
task.cancel(false);
|
||||
} else {
|
||||
this.timeoutTask = task;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// creates latch if required; return true if caller needs to wait
|
||||
private boolean prepareForWait() {
|
||||
synchronized (this) {
|
||||
if (haveResult) {
|
||||
return false;
|
||||
} else {
|
||||
if (latch == null)
|
||||
latch = new CountDownLatch(1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the result, or a no-op if the result or exception is already set.
|
||||
*/
|
||||
void setResult(V res) {
|
||||
synchronized (this) {
|
||||
if (haveResult)
|
||||
return;
|
||||
result = res;
|
||||
haveResult = true;
|
||||
if (timeoutTask != null)
|
||||
timeoutTask.cancel(false);
|
||||
if (latch != null)
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the result, or a no-op if the result or exception is already set.
|
||||
*/
|
||||
void setFailure(Throwable x) {
|
||||
if (!(x instanceof IOException) && !(x instanceof SecurityException))
|
||||
x = new IOException(x);
|
||||
synchronized (this) {
|
||||
if (haveResult)
|
||||
return;
|
||||
exc = x;
|
||||
haveResult = true;
|
||||
if (timeoutTask != null)
|
||||
timeoutTask.cancel(false);
|
||||
if (latch != null)
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the result
|
||||
*/
|
||||
void setResult(V res, Throwable x) {
|
||||
if (x == null) {
|
||||
setResult(res);
|
||||
} else {
|
||||
setFailure(x);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get() throws ExecutionException, InterruptedException {
|
||||
if (!haveResult) {
|
||||
boolean needToWait = prepareForWait();
|
||||
if (needToWait)
|
||||
latch.await();
|
||||
}
|
||||
if (exc != null) {
|
||||
if (exc == CANCELLED)
|
||||
throw new CancellationException();
|
||||
throw new ExecutionException(exc);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(long timeout, TimeUnit unit)
|
||||
throws ExecutionException, InterruptedException, TimeoutException
|
||||
{
|
||||
if (!haveResult) {
|
||||
boolean needToWait = prepareForWait();
|
||||
if (needToWait)
|
||||
if (!latch.await(timeout, unit)) throw new TimeoutException();
|
||||
}
|
||||
if (exc != null) {
|
||||
if (exc == CANCELLED)
|
||||
throw new CancellationException();
|
||||
throw new ExecutionException(exc);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Throwable exception() {
|
||||
return (exc != CANCELLED) ? exc : null;
|
||||
}
|
||||
|
||||
V value() {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return (exc == CANCELLED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
return haveResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
synchronized (this) {
|
||||
if (haveResult)
|
||||
return false; // already completed
|
||||
|
||||
// notify channel
|
||||
if (channel() instanceof Cancellable)
|
||||
((Cancellable)channel()).onCancel(this);
|
||||
|
||||
// set result and cancel timer
|
||||
exc = CANCELLED;
|
||||
haveResult = true;
|
||||
if (timeoutTask != null)
|
||||
timeoutTask.cancel(false);
|
||||
}
|
||||
|
||||
// close channel if forceful cancel
|
||||
if (mayInterruptIfRunning) {
|
||||
try {
|
||||
channel().close();
|
||||
} catch (IOException ignore) { }
|
||||
}
|
||||
|
||||
// release waiters
|
||||
if (latch != null)
|
||||
latch.countDown();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
163
jdkSrc/jdk8/sun/nio/ch/PendingIoCache.java
Normal file
163
jdkSrc/jdk8/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 sun.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
jdkSrc/jdk8/sun/nio/ch/PipeImpl.java
Normal file
185
jdkSrc/jdk8/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
jdkSrc/jdk8/sun/nio/ch/PollArrayWrapper.java
Normal file
115
jdkSrc/jdk8/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);
|
||||
}
|
||||
}
|
||||
42
jdkSrc/jdk8/sun/nio/ch/PollSelectorProvider.java
Normal file
42
jdkSrc/jdk8/sun/nio/ch/PollSelectorProvider.java
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2003, 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.*;
|
||||
import java.nio.channels.spi.*;
|
||||
|
||||
public class PollSelectorProvider
|
||||
extends SelectorProviderImpl
|
||||
{
|
||||
public AbstractSelector openSelector() throws IOException {
|
||||
return new PollSelectorImpl(this);
|
||||
}
|
||||
|
||||
public Channel inheritedChannel() throws IOException {
|
||||
return InheritedChannel.getChannel();
|
||||
}
|
||||
}
|
||||
159
jdkSrc/jdk8/sun/nio/ch/Reflect.java
Normal file
159
jdkSrc/jdk8/sun/nio/ch/Reflect.java
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 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.io.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
|
||||
class Reflect { // package-private
|
||||
|
||||
private Reflect() { }
|
||||
|
||||
private static class ReflectionError extends Error {
|
||||
private static final long serialVersionUID = -8659519328078164097L;
|
||||
ReflectionError(Throwable x) {
|
||||
super(x);
|
||||
}
|
||||
}
|
||||
|
||||
private static void setAccessible(final AccessibleObject ao) {
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
ao.setAccessible(true);
|
||||
return null;
|
||||
}});
|
||||
}
|
||||
|
||||
static Constructor<?> lookupConstructor(String className,
|
||||
Class<?>[] paramTypes)
|
||||
{
|
||||
try {
|
||||
Class<?> cl = Class.forName(className);
|
||||
Constructor<?> c = cl.getDeclaredConstructor(paramTypes);
|
||||
setAccessible(c);
|
||||
return c;
|
||||
} catch (ClassNotFoundException | NoSuchMethodException x) {
|
||||
throw new ReflectionError(x);
|
||||
}
|
||||
}
|
||||
|
||||
static Object invoke(Constructor<?> c, Object[] args) {
|
||||
try {
|
||||
return c.newInstance(args);
|
||||
} catch (InstantiationException |
|
||||
IllegalAccessException |
|
||||
InvocationTargetException x) {
|
||||
throw new ReflectionError(x);
|
||||
}
|
||||
}
|
||||
|
||||
static Method lookupMethod(String className,
|
||||
String methodName,
|
||||
Class... paramTypes)
|
||||
{
|
||||
try {
|
||||
Class<?> cl = Class.forName(className);
|
||||
Method m = cl.getDeclaredMethod(methodName, paramTypes);
|
||||
setAccessible(m);
|
||||
return m;
|
||||
} catch (ClassNotFoundException | NoSuchMethodException x) {
|
||||
throw new ReflectionError(x);
|
||||
}
|
||||
}
|
||||
|
||||
static Object invoke(Method m, Object ob, Object[] args) {
|
||||
try {
|
||||
return m.invoke(ob, args);
|
||||
} catch (IllegalAccessException | InvocationTargetException x) {
|
||||
throw new ReflectionError(x);
|
||||
}
|
||||
}
|
||||
|
||||
static Object invokeIO(Method m, Object ob, Object[] args)
|
||||
throws IOException
|
||||
{
|
||||
try {
|
||||
return m.invoke(ob, args);
|
||||
} catch (IllegalAccessException x) {
|
||||
throw new ReflectionError(x);
|
||||
} catch (InvocationTargetException x) {
|
||||
if (IOException.class.isInstance(x.getCause()))
|
||||
throw (IOException)x.getCause();
|
||||
throw new ReflectionError(x);
|
||||
}
|
||||
}
|
||||
|
||||
static Field lookupField(String className, String fieldName) {
|
||||
try {
|
||||
Class<?> cl = Class.forName(className);
|
||||
Field f = cl.getDeclaredField(fieldName);
|
||||
setAccessible(f);
|
||||
return f;
|
||||
} catch (ClassNotFoundException | NoSuchFieldException x) {
|
||||
throw new ReflectionError(x);
|
||||
}
|
||||
}
|
||||
|
||||
static Object get(Object ob, Field f) {
|
||||
try {
|
||||
return f.get(ob);
|
||||
} catch (IllegalAccessException x) {
|
||||
throw new ReflectionError(x);
|
||||
}
|
||||
}
|
||||
|
||||
static Object get(Field f) {
|
||||
return get(null, f);
|
||||
}
|
||||
|
||||
static void set(Object ob, Field f, Object val) {
|
||||
try {
|
||||
f.set(ob, val);
|
||||
} catch (IllegalAccessException x) {
|
||||
throw new ReflectionError(x);
|
||||
}
|
||||
}
|
||||
|
||||
static void setInt(Object ob, Field f, int val) {
|
||||
try {
|
||||
f.setInt(ob, val);
|
||||
} catch (IllegalAccessException x) {
|
||||
throw new ReflectionError(x);
|
||||
}
|
||||
}
|
||||
|
||||
static void setBoolean(Object ob, Field f, boolean val) {
|
||||
try {
|
||||
f.setBoolean(ob, val);
|
||||
} catch (IllegalAccessException x) {
|
||||
throw new ReflectionError(x);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
63
jdkSrc/jdk8/sun/nio/ch/Secrets.java
Normal file
63
jdkSrc/jdk8/sun/nio/ch/Secrets.java
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 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.SocketChannel;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Provides access to implementation private constructors and methods.
|
||||
*/
|
||||
|
||||
public final class Secrets {
|
||||
private Secrets() { }
|
||||
|
||||
private static SelectorProvider provider() {
|
||||
SelectorProvider p = SelectorProvider.provider();
|
||||
if (!(p instanceof SelectorProviderImpl))
|
||||
throw new UnsupportedOperationException();
|
||||
return p;
|
||||
}
|
||||
|
||||
public static SocketChannel newSocketChannel(FileDescriptor fd) {
|
||||
try {
|
||||
return new SocketChannelImpl(provider(), fd, false);
|
||||
} catch (IOException ioe) {
|
||||
throw new AssertionError(ioe);
|
||||
}
|
||||
}
|
||||
|
||||
public static ServerSocketChannel newServerSocketChannel(FileDescriptor fd) {
|
||||
try {
|
||||
return new ServerSocketChannelImpl(provider(), fd, false);
|
||||
} catch (IOException ioe) {
|
||||
throw new AssertionError(ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
71
jdkSrc/jdk8/sun/nio/ch/SelChImpl.java
Normal file
71
jdkSrc/jdk8/sun/nio/ch/SelChImpl.java
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 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;
|
||||
|
||||
import java.nio.channels.Channel;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* An interface that allows translation (and more!).
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
|
||||
public interface SelChImpl extends Channel {
|
||||
|
||||
FileDescriptor getFD();
|
||||
|
||||
int getFDVal();
|
||||
|
||||
/**
|
||||
* Adds the specified ops if present in interestOps. The specified
|
||||
* ops are turned on without affecting the other ops.
|
||||
*
|
||||
* @return true iff the new value of sk.readyOps() set by this method
|
||||
* contains at least one bit that the previous value did not
|
||||
* contain
|
||||
*/
|
||||
public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk);
|
||||
|
||||
/**
|
||||
* Sets the specified ops if present in interestOps. The specified
|
||||
* ops are turned on, and all other ops are turned off.
|
||||
*
|
||||
* @return true iff the new value of sk.readyOps() set by this method
|
||||
* contains at least one bit that the previous value did not
|
||||
* contain
|
||||
*/
|
||||
public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk);
|
||||
|
||||
void translateAndSetInterestOps(int ops, SelectionKeyImpl sk);
|
||||
|
||||
int validOps();
|
||||
|
||||
void kill() throws IOException;
|
||||
|
||||
}
|
||||
114
jdkSrc/jdk8/sun/nio/ch/SelectionKeyImpl.java
Normal file
114
jdkSrc/jdk8/sun/nio/ch/SelectionKeyImpl.java
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.*;
|
||||
import java.nio.channels.spi.*;
|
||||
|
||||
|
||||
/**
|
||||
* An implementation of SelectionKey for Solaris.
|
||||
*/
|
||||
|
||||
public class SelectionKeyImpl
|
||||
extends AbstractSelectionKey
|
||||
{
|
||||
|
||||
final SelChImpl channel; // package-private
|
||||
public final SelectorImpl selector;
|
||||
|
||||
// Index for a pollfd array in Selector that this key is registered with
|
||||
private int index;
|
||||
|
||||
private volatile int interestOps;
|
||||
private int readyOps;
|
||||
|
||||
SelectionKeyImpl(SelChImpl ch, SelectorImpl sel) {
|
||||
channel = ch;
|
||||
selector = sel;
|
||||
}
|
||||
|
||||
public SelectableChannel channel() {
|
||||
return (SelectableChannel)channel;
|
||||
}
|
||||
|
||||
public Selector selector() {
|
||||
return selector;
|
||||
}
|
||||
|
||||
int getIndex() { // package-private
|
||||
return index;
|
||||
}
|
||||
|
||||
void setIndex(int i) { // package-private
|
||||
index = i;
|
||||
}
|
||||
|
||||
private void ensureValid() {
|
||||
if (!isValid())
|
||||
throw new CancelledKeyException();
|
||||
}
|
||||
|
||||
public int interestOps() {
|
||||
ensureValid();
|
||||
return interestOps;
|
||||
}
|
||||
|
||||
public SelectionKey interestOps(int ops) {
|
||||
ensureValid();
|
||||
return nioInterestOps(ops);
|
||||
}
|
||||
|
||||
public int readyOps() {
|
||||
ensureValid();
|
||||
return readyOps;
|
||||
}
|
||||
|
||||
// The nio versions of these operations do not care if a key
|
||||
// has been invalidated. They are for internal use by nio code.
|
||||
|
||||
public void nioReadyOps(int ops) {
|
||||
readyOps = ops;
|
||||
}
|
||||
|
||||
public int nioReadyOps() {
|
||||
return readyOps;
|
||||
}
|
||||
|
||||
public SelectionKey nioInterestOps(int ops) {
|
||||
if ((ops & ~channel().validOps()) != 0)
|
||||
throw new IllegalArgumentException();
|
||||
channel.translateAndSetInterestOps(ops, this);
|
||||
interestOps = ops;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int nioInterestOps() {
|
||||
return interestOps;
|
||||
}
|
||||
|
||||
}
|
||||
164
jdkSrc/jdk8/sun/nio/ch/SelectorImpl.java
Normal file
164
jdkSrc/jdk8/sun/nio/ch/SelectorImpl.java
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.*;
|
||||
import java.nio.channels.spi.*;
|
||||
import java.net.SocketException;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
/**
|
||||
* Base Selector implementation class.
|
||||
*/
|
||||
|
||||
public abstract class SelectorImpl
|
||||
extends AbstractSelector
|
||||
{
|
||||
|
||||
// The set of keys with data ready for an operation
|
||||
protected Set<SelectionKey> selectedKeys;
|
||||
|
||||
// The set of keys registered with this Selector
|
||||
protected HashSet<SelectionKey> keys;
|
||||
|
||||
// Public views of the key sets
|
||||
private Set<SelectionKey> publicKeys; // Immutable
|
||||
private Set<SelectionKey> publicSelectedKeys; // Removal allowed, but not addition
|
||||
|
||||
protected SelectorImpl(SelectorProvider sp) {
|
||||
super(sp);
|
||||
keys = new HashSet<SelectionKey>();
|
||||
selectedKeys = new HashSet<SelectionKey>();
|
||||
if (Util.atBugLevel("1.4")) {
|
||||
publicKeys = keys;
|
||||
publicSelectedKeys = selectedKeys;
|
||||
} else {
|
||||
publicKeys = Collections.unmodifiableSet(keys);
|
||||
publicSelectedKeys = Util.ungrowableSet(selectedKeys);
|
||||
}
|
||||
}
|
||||
|
||||
public Set<SelectionKey> keys() {
|
||||
if (!isOpen() && !Util.atBugLevel("1.4"))
|
||||
throw new ClosedSelectorException();
|
||||
return publicKeys;
|
||||
}
|
||||
|
||||
public Set<SelectionKey> selectedKeys() {
|
||||
if (!isOpen() && !Util.atBugLevel("1.4"))
|
||||
throw new ClosedSelectorException();
|
||||
return publicSelectedKeys;
|
||||
}
|
||||
|
||||
protected abstract int doSelect(long timeout) throws IOException;
|
||||
|
||||
private int lockAndDoSelect(long timeout) throws IOException {
|
||||
synchronized (this) {
|
||||
if (!isOpen())
|
||||
throw new ClosedSelectorException();
|
||||
synchronized (publicKeys) {
|
||||
synchronized (publicSelectedKeys) {
|
||||
return doSelect(timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int select(long timeout)
|
||||
throws IOException
|
||||
{
|
||||
if (timeout < 0)
|
||||
throw new IllegalArgumentException("Negative timeout");
|
||||
return lockAndDoSelect((timeout == 0) ? -1 : timeout);
|
||||
}
|
||||
|
||||
public int select() throws IOException {
|
||||
return select(0);
|
||||
}
|
||||
|
||||
public int selectNow() throws IOException {
|
||||
return lockAndDoSelect(0);
|
||||
}
|
||||
|
||||
public void implCloseSelector() throws IOException {
|
||||
wakeup();
|
||||
synchronized (this) {
|
||||
synchronized (publicKeys) {
|
||||
synchronized (publicSelectedKeys) {
|
||||
implClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void implClose() throws IOException;
|
||||
|
||||
public void putEventOps(SelectionKeyImpl sk, int ops) { }
|
||||
|
||||
protected final SelectionKey register(AbstractSelectableChannel ch,
|
||||
int ops,
|
||||
Object attachment)
|
||||
{
|
||||
if (!(ch instanceof SelChImpl))
|
||||
throw new IllegalSelectorException();
|
||||
SelectionKeyImpl k = new SelectionKeyImpl((SelChImpl)ch, this);
|
||||
k.attach(attachment);
|
||||
synchronized (publicKeys) {
|
||||
implRegister(k);
|
||||
}
|
||||
k.interestOps(ops);
|
||||
return k;
|
||||
}
|
||||
|
||||
protected abstract void implRegister(SelectionKeyImpl ski);
|
||||
|
||||
void processDeregisterQueue() throws IOException {
|
||||
// Precondition: Synchronized on this, keys, and selectedKeys
|
||||
Set<SelectionKey> cks = cancelledKeys();
|
||||
synchronized (cks) {
|
||||
if (!cks.isEmpty()) {
|
||||
Iterator<SelectionKey> i = cks.iterator();
|
||||
while (i.hasNext()) {
|
||||
SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
|
||||
try {
|
||||
implDereg(ski);
|
||||
} catch (SocketException se) {
|
||||
throw new IOException("Error deregistering key", se);
|
||||
} finally {
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void implDereg(SelectionKeyImpl ski) throws IOException;
|
||||
|
||||
abstract public Selector wakeup();
|
||||
|
||||
}
|
||||
62
jdkSrc/jdk8/sun/nio/ch/SelectorProviderImpl.java
Normal file
62
jdkSrc/jdk8/sun/nio/ch/SelectorProviderImpl.java
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2008, 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 java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.ProtocolFamily;
|
||||
import java.nio.channels.*;
|
||||
import java.nio.channels.spi.*;
|
||||
|
||||
|
||||
public abstract class SelectorProviderImpl
|
||||
extends SelectorProvider
|
||||
{
|
||||
|
||||
public DatagramChannel openDatagramChannel() throws IOException {
|
||||
return new DatagramChannelImpl(this);
|
||||
}
|
||||
|
||||
public DatagramChannel openDatagramChannel(ProtocolFamily family) throws IOException {
|
||||
return new DatagramChannelImpl(this, family);
|
||||
}
|
||||
|
||||
public Pipe openPipe() throws IOException {
|
||||
return new PipeImpl(this);
|
||||
}
|
||||
|
||||
public abstract AbstractSelector openSelector() throws IOException;
|
||||
|
||||
public ServerSocketChannel openServerSocketChannel() throws IOException {
|
||||
return new ServerSocketChannelImpl(this);
|
||||
}
|
||||
|
||||
public SocketChannel openSocketChannel() throws IOException {
|
||||
return new SocketChannelImpl(this);
|
||||
}
|
||||
}
|
||||
219
jdkSrc/jdk8/sun/nio/ch/ServerSocketAdaptor.java
Normal file
219
jdkSrc/jdk8/sun/nio/ch/ServerSocketAdaptor.java
Normal file
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2018, 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.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.SocketException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.StandardSocketOptions;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.IllegalBlockingModeException;
|
||||
import java.nio.channels.NotYetBoundException;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.nio.channels.SocketChannel;
|
||||
|
||||
|
||||
// Make a server-socket channel look like a server socket.
|
||||
//
|
||||
// The methods in this class are defined in exactly the same order as in
|
||||
// java.net.ServerSocket so as to simplify tracking future changes to that
|
||||
// class.
|
||||
//
|
||||
|
||||
class ServerSocketAdaptor // package-private
|
||||
extends ServerSocket
|
||||
{
|
||||
|
||||
// The channel being adapted
|
||||
private final ServerSocketChannelImpl ssc;
|
||||
|
||||
// Timeout "option" value for accepts
|
||||
private volatile int timeout = 0;
|
||||
|
||||
public static ServerSocket create(ServerSocketChannelImpl ssc) {
|
||||
try {
|
||||
return new ServerSocketAdaptor(ssc);
|
||||
} catch (IOException x) {
|
||||
throw new Error(x);
|
||||
}
|
||||
}
|
||||
|
||||
// ## super will create a useless impl
|
||||
private ServerSocketAdaptor(ServerSocketChannelImpl ssc)
|
||||
throws IOException
|
||||
{
|
||||
this.ssc = ssc;
|
||||
}
|
||||
|
||||
|
||||
public void bind(SocketAddress local) throws IOException {
|
||||
bind(local, 50);
|
||||
}
|
||||
|
||||
public void bind(SocketAddress local, int backlog) throws IOException {
|
||||
if (local == null)
|
||||
local = new InetSocketAddress(0);
|
||||
try {
|
||||
ssc.bind(local, backlog);
|
||||
} catch (Exception x) {
|
||||
Net.translateException(x);
|
||||
}
|
||||
}
|
||||
|
||||
public InetAddress getInetAddress() {
|
||||
if (!ssc.isBound())
|
||||
return null;
|
||||
return Net.getRevealedLocalAddress(ssc.localAddress()).getAddress();
|
||||
|
||||
}
|
||||
|
||||
public int getLocalPort() {
|
||||
if (!ssc.isBound())
|
||||
return -1;
|
||||
return Net.asInetSocketAddress(ssc.localAddress()).getPort();
|
||||
}
|
||||
|
||||
|
||||
public Socket accept() throws IOException {
|
||||
synchronized (ssc.blockingLock()) {
|
||||
if (!ssc.isBound())
|
||||
throw new IllegalBlockingModeException();
|
||||
try {
|
||||
if (timeout == 0) {
|
||||
// for compatibility reasons: accept connection if available
|
||||
// when configured non-blocking
|
||||
SocketChannel sc = ssc.accept();
|
||||
if (sc == null && !ssc.isBlocking())
|
||||
throw new IllegalBlockingModeException();
|
||||
return sc.socket();
|
||||
}
|
||||
|
||||
if (!ssc.isBlocking())
|
||||
throw new IllegalBlockingModeException();
|
||||
ssc.configureBlocking(false);
|
||||
try {
|
||||
SocketChannel sc;
|
||||
if ((sc = ssc.accept()) != null)
|
||||
return sc.socket();
|
||||
long to = timeout;
|
||||
for (;;) {
|
||||
if (!ssc.isOpen())
|
||||
throw new ClosedChannelException();
|
||||
long st = System.currentTimeMillis();
|
||||
int result = ssc.poll(Net.POLLIN, to);
|
||||
if (result > 0 && ((sc = ssc.accept()) != null))
|
||||
return sc.socket();
|
||||
to -= System.currentTimeMillis() - st;
|
||||
if (to <= 0)
|
||||
throw new SocketTimeoutException();
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
ssc.configureBlocking(true);
|
||||
} catch (ClosedChannelException e) { }
|
||||
}
|
||||
} catch (Exception x) {
|
||||
Net.translateException(x);
|
||||
assert false;
|
||||
return null; // Never happens
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
ssc.close();
|
||||
}
|
||||
|
||||
public ServerSocketChannel getChannel() {
|
||||
return ssc;
|
||||
}
|
||||
|
||||
public boolean isBound() {
|
||||
return ssc.isBound();
|
||||
}
|
||||
|
||||
public boolean isClosed() {
|
||||
return !ssc.isOpen();
|
||||
}
|
||||
|
||||
public void setSoTimeout(int timeout) throws SocketException {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
public int getSoTimeout() throws SocketException {
|
||||
return timeout;
|
||||
}
|
||||
|
||||
public void setReuseAddress(boolean on) throws SocketException {
|
||||
try {
|
||||
ssc.setOption(StandardSocketOptions.SO_REUSEADDR, on);
|
||||
} catch (IOException x) {
|
||||
Net.translateToSocketException(x);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getReuseAddress() throws SocketException {
|
||||
try {
|
||||
return ssc.getOption(StandardSocketOptions.SO_REUSEADDR).booleanValue();
|
||||
} catch (IOException x) {
|
||||
Net.translateToSocketException(x);
|
||||
return false; // Never happens
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (!isBound())
|
||||
return "ServerSocket[unbound]";
|
||||
return "ServerSocket[addr=" + getInetAddress() +
|
||||
",localport=" + getLocalPort() + "]";
|
||||
}
|
||||
|
||||
public void setReceiveBufferSize(int size) throws SocketException {
|
||||
// size 0 valid for ServerSocketChannel, invalid for ServerSocket
|
||||
if (size <= 0)
|
||||
throw new IllegalArgumentException("size cannot be 0 or negative");
|
||||
try {
|
||||
ssc.setOption(StandardSocketOptions.SO_RCVBUF, size);
|
||||
} catch (IOException x) {
|
||||
Net.translateToSocketException(x);
|
||||
}
|
||||
}
|
||||
|
||||
public int getReceiveBufferSize() throws SocketException {
|
||||
try {
|
||||
return ssc.getOption(StandardSocketOptions.SO_RCVBUF).intValue();
|
||||
} catch (IOException x) {
|
||||
Net.translateToSocketException(x);
|
||||
return -1; // Never happens
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
443
jdkSrc/jdk8/sun/nio/ch/ServerSocketChannelImpl.java
Normal file
443
jdkSrc/jdk8/sun/nio/ch/ServerSocketChannelImpl.java
Normal file
@@ -0,0 +1,443 @@
|
||||
/*
|
||||
* 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.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.net.*;
|
||||
import java.nio.channels.*;
|
||||
import java.nio.channels.spi.*;
|
||||
import java.util.*;
|
||||
import sun.net.NetHooks;
|
||||
import sun.net.ExtendedOptionsHelper;
|
||||
|
||||
|
||||
/**
|
||||
* An implementation of ServerSocketChannels
|
||||
*/
|
||||
|
||||
class ServerSocketChannelImpl
|
||||
extends ServerSocketChannel
|
||||
implements SelChImpl
|
||||
{
|
||||
|
||||
// Used to make native close and configure calls
|
||||
private static NativeDispatcher nd;
|
||||
|
||||
// Our file descriptor
|
||||
private final FileDescriptor fd;
|
||||
private final int fdVal;
|
||||
|
||||
// ID of native thread currently blocked in this channel, for signalling
|
||||
private volatile long thread = 0;
|
||||
|
||||
// Lock held by thread currently blocked in this channel
|
||||
private final Object lock = new Object();
|
||||
|
||||
// Lock held by any thread that modifies the state fields declared below
|
||||
// DO NOT invoke a blocking I/O operation while holding this lock!
|
||||
private final Object stateLock = new Object();
|
||||
|
||||
// -- The following fields are protected by stateLock
|
||||
|
||||
// Channel state, increases monotonically
|
||||
private static final int ST_UNINITIALIZED = -1;
|
||||
private static final int ST_INUSE = 0;
|
||||
private static final int ST_KILLED = 1;
|
||||
private int state = ST_UNINITIALIZED;
|
||||
|
||||
// Binding
|
||||
private InetSocketAddress localAddress; // null => unbound
|
||||
|
||||
// set true when exclusive binding is on and SO_REUSEADDR is emulated
|
||||
private boolean isReuseAddress;
|
||||
|
||||
// Our socket adaptor, if any
|
||||
ServerSocket socket;
|
||||
|
||||
// -- End of fields protected by stateLock
|
||||
|
||||
|
||||
ServerSocketChannelImpl(SelectorProvider sp) throws IOException {
|
||||
super(sp);
|
||||
this.fd = Net.serverSocket(true);
|
||||
this.fdVal = IOUtil.fdVal(fd);
|
||||
this.state = ST_INUSE;
|
||||
}
|
||||
|
||||
ServerSocketChannelImpl(SelectorProvider sp,
|
||||
FileDescriptor fd,
|
||||
boolean bound)
|
||||
throws IOException
|
||||
{
|
||||
super(sp);
|
||||
this.fd = fd;
|
||||
this.fdVal = IOUtil.fdVal(fd);
|
||||
this.state = ST_INUSE;
|
||||
if (bound)
|
||||
localAddress = Net.localAddress(fd);
|
||||
}
|
||||
|
||||
public ServerSocket socket() {
|
||||
synchronized (stateLock) {
|
||||
if (socket == null)
|
||||
socket = ServerSocketAdaptor.create(this);
|
||||
return socket;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketAddress getLocalAddress() throws IOException {
|
||||
synchronized (stateLock) {
|
||||
if (!isOpen())
|
||||
throw new ClosedChannelException();
|
||||
return localAddress == null ? localAddress
|
||||
: Net.getRevealedLocalAddress(
|
||||
Net.asInetSocketAddress(localAddress));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ServerSocketChannel setOption(SocketOption<T> name, T value)
|
||||
throws IOException
|
||||
{
|
||||
if (name == null)
|
||||
throw new NullPointerException();
|
||||
if (!supportedOptions().contains(name))
|
||||
throw new UnsupportedOperationException("'" + name + "' not supported");
|
||||
synchronized (stateLock) {
|
||||
if (!isOpen())
|
||||
throw new ClosedChannelException();
|
||||
|
||||
if (name == StandardSocketOptions.IP_TOS) {
|
||||
ProtocolFamily family = Net.isIPv6Available() ?
|
||||
StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
|
||||
Net.setSocketOption(fd, family, name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
if (name == StandardSocketOptions.SO_REUSEADDR &&
|
||||
Net.useExclusiveBind())
|
||||
{
|
||||
// SO_REUSEADDR emulated when using exclusive bind
|
||||
isReuseAddress = (Boolean)value;
|
||||
} else {
|
||||
// no options that require special handling
|
||||
Net.setSocketOption(fd, Net.UNSPEC, name, value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getOption(SocketOption<T> name)
|
||||
throws IOException
|
||||
{
|
||||
if (name == null)
|
||||
throw new NullPointerException();
|
||||
if (!supportedOptions().contains(name))
|
||||
throw new UnsupportedOperationException("'" + name + "' not supported");
|
||||
|
||||
synchronized (stateLock) {
|
||||
if (!isOpen())
|
||||
throw new ClosedChannelException();
|
||||
if (name == StandardSocketOptions.SO_REUSEADDR &&
|
||||
Net.useExclusiveBind())
|
||||
{
|
||||
// SO_REUSEADDR emulated when using exclusive bind
|
||||
return (T)Boolean.valueOf(isReuseAddress);
|
||||
}
|
||||
// no options that require special handling
|
||||
return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
|
||||
}
|
||||
}
|
||||
|
||||
private static class DefaultOptionsHolder {
|
||||
static final Set<SocketOption<?>> defaultOptions = defaultOptions();
|
||||
|
||||
private static Set<SocketOption<?>> defaultOptions() {
|
||||
HashSet<SocketOption<?>> set = new HashSet<SocketOption<?>>(2);
|
||||
set.add(StandardSocketOptions.SO_RCVBUF);
|
||||
set.add(StandardSocketOptions.SO_REUSEADDR);
|
||||
set.add(StandardSocketOptions.IP_TOS);
|
||||
set.addAll(ExtendedOptionsHelper.keepAliveOptions());
|
||||
return Collections.unmodifiableSet(set);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Set<SocketOption<?>> supportedOptions() {
|
||||
return DefaultOptionsHolder.defaultOptions;
|
||||
}
|
||||
|
||||
public boolean isBound() {
|
||||
synchronized (stateLock) {
|
||||
return localAddress != null;
|
||||
}
|
||||
}
|
||||
|
||||
public InetSocketAddress localAddress() {
|
||||
synchronized (stateLock) {
|
||||
return localAddress;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException {
|
||||
synchronized (lock) {
|
||||
if (!isOpen())
|
||||
throw new ClosedChannelException();
|
||||
if (isBound())
|
||||
throw new AlreadyBoundException();
|
||||
InetSocketAddress isa = (local == null) ? new InetSocketAddress(0) :
|
||||
Net.checkAddress(local);
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null)
|
||||
sm.checkListen(isa.getPort());
|
||||
NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
|
||||
Net.bind(fd, isa.getAddress(), isa.getPort());
|
||||
Net.listen(fd, backlog < 1 ? 50 : backlog);
|
||||
synchronized (stateLock) {
|
||||
localAddress = Net.localAddress(fd);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public SocketChannel accept() throws IOException {
|
||||
synchronized (lock) {
|
||||
if (!isOpen())
|
||||
throw new ClosedChannelException();
|
||||
if (!isBound())
|
||||
throw new NotYetBoundException();
|
||||
SocketChannel sc = null;
|
||||
|
||||
int n = 0;
|
||||
FileDescriptor newfd = new FileDescriptor();
|
||||
InetSocketAddress[] isaa = new InetSocketAddress[1];
|
||||
|
||||
try {
|
||||
begin();
|
||||
if (!isOpen())
|
||||
return null;
|
||||
thread = NativeThread.current();
|
||||
for (;;) {
|
||||
n = accept(this.fd, newfd, isaa);
|
||||
if ((n == IOStatus.INTERRUPTED) && isOpen())
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
} finally {
|
||||
thread = 0;
|
||||
end(n > 0);
|
||||
assert IOStatus.check(n);
|
||||
}
|
||||
|
||||
if (n < 1)
|
||||
return null;
|
||||
|
||||
IOUtil.configureBlocking(newfd, true);
|
||||
InetSocketAddress isa = isaa[0];
|
||||
sc = new SocketChannelImpl(provider(), newfd, isa);
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
try {
|
||||
sm.checkAccept(isa.getAddress().getHostAddress(),
|
||||
isa.getPort());
|
||||
} catch (SecurityException x) {
|
||||
sc.close();
|
||||
throw x;
|
||||
}
|
||||
}
|
||||
return sc;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
protected void implConfigureBlocking(boolean block) throws IOException {
|
||||
IOUtil.configureBlocking(fd, block);
|
||||
}
|
||||
|
||||
protected void implCloseSelectableChannel() throws IOException {
|
||||
synchronized (stateLock) {
|
||||
if (state != ST_KILLED)
|
||||
nd.preClose(fd);
|
||||
long th = thread;
|
||||
if (th != 0)
|
||||
NativeThread.signal(th);
|
||||
if (!isRegistered())
|
||||
kill();
|
||||
}
|
||||
}
|
||||
|
||||
public void kill() throws IOException {
|
||||
synchronized (stateLock) {
|
||||
if (state == ST_KILLED)
|
||||
return;
|
||||
if (state == ST_UNINITIALIZED) {
|
||||
state = ST_KILLED;
|
||||
return;
|
||||
}
|
||||
assert !isOpen() && !isRegistered();
|
||||
nd.close(fd);
|
||||
state = ST_KILLED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates native poll revent set into a ready operation set
|
||||
*/
|
||||
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) {
|
||||
// This should only happen if this channel is pre-closed while a
|
||||
// selection operation is in progress
|
||||
// ## Throw an error if this channel has not been pre-closed
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
|
||||
newOps = intOps;
|
||||
sk.nioReadyOps(newOps);
|
||||
return (newOps & ~oldOps) != 0;
|
||||
}
|
||||
|
||||
if (((ops & Net.POLLIN) != 0) &&
|
||||
((intOps & SelectionKey.OP_ACCEPT) != 0))
|
||||
newOps |= SelectionKey.OP_ACCEPT;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// package-private
|
||||
int poll(int events, long timeout) throws IOException {
|
||||
assert Thread.holdsLock(blockingLock()) && !isBlocking();
|
||||
|
||||
synchronized (lock) {
|
||||
int n = 0;
|
||||
try {
|
||||
begin();
|
||||
synchronized (stateLock) {
|
||||
if (!isOpen())
|
||||
return 0;
|
||||
thread = NativeThread.current();
|
||||
}
|
||||
n = Net.poll(fd, events, timeout);
|
||||
} finally {
|
||||
thread = 0;
|
||||
end(n > 0);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates an interest operation set into a native poll event set
|
||||
*/
|
||||
public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
|
||||
int newOps = 0;
|
||||
|
||||
// Translate ops
|
||||
if ((ops & SelectionKey.OP_ACCEPT) != 0)
|
||||
newOps |= Net.POLLIN;
|
||||
// Place ops into pollfd array
|
||||
sk.selector.putEventOps(sk, newOps);
|
||||
}
|
||||
|
||||
public FileDescriptor getFD() {
|
||||
return fd;
|
||||
}
|
||||
|
||||
public int getFDVal() {
|
||||
return fdVal;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(this.getClass().getName());
|
||||
sb.append('[');
|
||||
if (!isOpen()) {
|
||||
sb.append("closed");
|
||||
} else {
|
||||
synchronized (stateLock) {
|
||||
InetSocketAddress addr = localAddress();
|
||||
if (addr == null) {
|
||||
sb.append("unbound");
|
||||
} else {
|
||||
sb.append(Net.getRevealedLocalAddressAsString(addr));
|
||||
}
|
||||
}
|
||||
}
|
||||
sb.append(']');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept a connection on a socket.
|
||||
*
|
||||
* @implNote Wrap native call to allow instrumentation.
|
||||
*/
|
||||
private int accept(FileDescriptor ssfd, FileDescriptor newfd,
|
||||
InetSocketAddress[] isaa)
|
||||
throws IOException
|
||||
{
|
||||
return accept0(ssfd, newfd, isaa);
|
||||
}
|
||||
|
||||
// -- Native methods --
|
||||
|
||||
// Accepts a new connection, setting the given file descriptor to refer to
|
||||
// the new socket and setting isaa[0] to the socket's remote address.
|
||||
// Returns 1 on success, or IOStatus.UNAVAILABLE (if non-blocking and no
|
||||
// connections are pending) or IOStatus.INTERRUPTED.
|
||||
//
|
||||
private native int accept0(FileDescriptor ssfd, FileDescriptor newfd,
|
||||
InetSocketAddress[] isaa)
|
||||
throws IOException;
|
||||
|
||||
private static native void initIDs();
|
||||
|
||||
static {
|
||||
IOUtil.load();
|
||||
initIDs();
|
||||
nd = new SocketDispatcher();
|
||||
}
|
||||
|
||||
}
|
||||
396
jdkSrc/jdk8/sun/nio/ch/SimpleAsynchronousFileChannelImpl.java
Normal file
396
jdkSrc/jdk8/sun/nio/ch/SimpleAsynchronousFileChannelImpl.java
Normal file
@@ -0,0 +1,396 @@
|
||||
/*
|
||||
* 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.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* "Portable" implementation of AsynchronousFileChannel for use on operating
|
||||
* systems that don't support asynchronous file I/O.
|
||||
*/
|
||||
|
||||
public class SimpleAsynchronousFileChannelImpl
|
||||
extends AsynchronousFileChannelImpl
|
||||
{
|
||||
// lazy initialization of default thread pool for file I/O
|
||||
private static class DefaultExecutorHolder {
|
||||
static final ExecutorService defaultExecutor =
|
||||
ThreadPool.createDefault().executor();
|
||||
}
|
||||
|
||||
// Used to make native read and write calls
|
||||
private static final FileDispatcher nd = new FileDispatcherImpl();
|
||||
|
||||
// Thread-safe set of IDs of native threads, for signalling
|
||||
private final NativeThreadSet threads = new NativeThreadSet(2);
|
||||
|
||||
|
||||
SimpleAsynchronousFileChannelImpl(FileDescriptor fdObj,
|
||||
boolean reading,
|
||||
boolean writing,
|
||||
ExecutorService executor)
|
||||
{
|
||||
super(fdObj, reading, writing, executor);
|
||||
}
|
||||
|
||||
public static AsynchronousFileChannel open(FileDescriptor fdo,
|
||||
boolean reading,
|
||||
boolean writing,
|
||||
ThreadPool pool)
|
||||
{
|
||||
// Executor is either default or based on pool parameters
|
||||
ExecutorService executor = (pool == null) ?
|
||||
DefaultExecutorHolder.defaultExecutor : pool.executor();
|
||||
return new SimpleAsynchronousFileChannelImpl(fdo, reading, writing, executor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
// mark channel as closed
|
||||
synchronized (fdObj) {
|
||||
if (closed)
|
||||
return; // already closed
|
||||
closed = true;
|
||||
// from this point on, if another thread invokes the begin() method
|
||||
// then it will throw ClosedChannelException
|
||||
}
|
||||
|
||||
// Invalidate and release any locks that we still hold
|
||||
invalidateAllLocks();
|
||||
|
||||
// signal any threads blocked on this channel
|
||||
threads.signalAndWait();
|
||||
|
||||
// wait until all async I/O operations have completely gracefully
|
||||
closeLock.writeLock().lock();
|
||||
try {
|
||||
// do nothing
|
||||
} finally {
|
||||
closeLock.writeLock().unlock();
|
||||
}
|
||||
|
||||
// close file
|
||||
nd.close(fdObj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long size() throws IOException {
|
||||
int ti = threads.add();
|
||||
try {
|
||||
long n = 0L;
|
||||
try {
|
||||
begin();
|
||||
do {
|
||||
n = nd.size(fdObj);
|
||||
} while ((n == IOStatus.INTERRUPTED) && isOpen());
|
||||
return n;
|
||||
} finally {
|
||||
end(n >= 0L);
|
||||
}
|
||||
} finally {
|
||||
threads.remove(ti);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousFileChannel truncate(long size) throws IOException {
|
||||
if (size < 0L)
|
||||
throw new IllegalArgumentException("Negative size");
|
||||
if (!writing)
|
||||
throw new NonWritableChannelException();
|
||||
int ti = threads.add();
|
||||
try {
|
||||
long n = 0L;
|
||||
try {
|
||||
begin();
|
||||
do {
|
||||
n = nd.size(fdObj);
|
||||
} while ((n == IOStatus.INTERRUPTED) && isOpen());
|
||||
|
||||
// truncate file if 'size' less than current size
|
||||
if (size < n && isOpen()) {
|
||||
do {
|
||||
n = nd.truncate(fdObj, size);
|
||||
} while ((n == IOStatus.INTERRUPTED) && isOpen());
|
||||
}
|
||||
return this;
|
||||
} finally {
|
||||
end(n > 0);
|
||||
}
|
||||
} finally {
|
||||
threads.remove(ti);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void force(boolean metaData) throws IOException {
|
||||
int ti = threads.add();
|
||||
try {
|
||||
int n = 0;
|
||||
try {
|
||||
begin();
|
||||
do {
|
||||
n = nd.force(fdObj, metaData);
|
||||
} while ((n == IOStatus.INTERRUPTED) && isOpen());
|
||||
} finally {
|
||||
end(n >= 0);
|
||||
}
|
||||
} finally {
|
||||
threads.remove(ti);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
<A> Future<FileLock> implLock(final long position,
|
||||
final long size,
|
||||
final boolean shared,
|
||||
final A attachment,
|
||||
final CompletionHandler<FileLock,? super A> handler)
|
||||
{
|
||||
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) {
|
||||
Throwable exc = new ClosedChannelException();
|
||||
if (handler == null)
|
||||
return CompletedFuture.withFailure(exc);
|
||||
Invoker.invokeIndirectly(handler, attachment, null, exc, executor);
|
||||
return null;
|
||||
}
|
||||
|
||||
final PendingFuture<FileLock,A> result = (handler == null) ?
|
||||
new PendingFuture<FileLock,A>(this) : null;
|
||||
Runnable task = new Runnable() {
|
||||
public void run() {
|
||||
Throwable exc = null;
|
||||
|
||||
int ti = threads.add();
|
||||
try {
|
||||
int n;
|
||||
try {
|
||||
begin();
|
||||
do {
|
||||
n = nd.lock(fdObj, true, position, size, shared);
|
||||
} while ((n == FileDispatcher.INTERRUPTED) && isOpen());
|
||||
if (n != FileDispatcher.LOCKED || !isOpen()) {
|
||||
throw new AsynchronousCloseException();
|
||||
}
|
||||
} catch (IOException x) {
|
||||
removeFromFileLockTable(fli);
|
||||
if (!isOpen())
|
||||
x = new AsynchronousCloseException();
|
||||
exc = x;
|
||||
} finally {
|
||||
end();
|
||||
}
|
||||
} finally {
|
||||
threads.remove(ti);
|
||||
}
|
||||
if (handler == null) {
|
||||
result.setResult(fli, exc);
|
||||
} else {
|
||||
Invoker.invokeUnchecked(handler, attachment, fli, exc);
|
||||
}
|
||||
}
|
||||
};
|
||||
boolean executed = false;
|
||||
try {
|
||||
executor.execute(task);
|
||||
executed = true;
|
||||
} finally {
|
||||
if (!executed) {
|
||||
// rollback
|
||||
removeFromFileLockTable(fli);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@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
|
||||
FileLockImpl fli = addToFileLockTable(position, size, shared);
|
||||
if (fli == null)
|
||||
throw new ClosedChannelException();
|
||||
|
||||
int ti = threads.add();
|
||||
boolean gotLock = false;
|
||||
try {
|
||||
begin();
|
||||
int n;
|
||||
do {
|
||||
n = nd.lock(fdObj, false, position, size, shared);
|
||||
} while ((n == FileDispatcher.INTERRUPTED) && isOpen());
|
||||
if (n == FileDispatcher.LOCKED && isOpen()) {
|
||||
gotLock = true;
|
||||
return fli; // lock acquired
|
||||
}
|
||||
if (n == FileDispatcher.NO_LOCK)
|
||||
return null; // locked by someone else
|
||||
if (n == FileDispatcher.INTERRUPTED)
|
||||
throw new AsynchronousCloseException();
|
||||
// should not get here
|
||||
throw new AssertionError();
|
||||
} finally {
|
||||
if (!gotLock)
|
||||
removeFromFileLockTable(fli);
|
||||
end();
|
||||
threads.remove(ti);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void implRelease(FileLockImpl fli) throws IOException {
|
||||
nd.release(fdObj, fli.position(), fli.size());
|
||||
}
|
||||
|
||||
@Override
|
||||
<A> Future<Integer> implRead(final ByteBuffer dst,
|
||||
final long position,
|
||||
final A attachment,
|
||||
final CompletionHandler<Integer,? super A> handler)
|
||||
{
|
||||
if (position < 0)
|
||||
throw new IllegalArgumentException("Negative position");
|
||||
if (!reading)
|
||||
throw new NonReadableChannelException();
|
||||
if (dst.isReadOnly())
|
||||
throw new IllegalArgumentException("Read-only buffer");
|
||||
|
||||
// complete immediately if channel closed or no space remaining
|
||||
if (!isOpen() || (dst.remaining() == 0)) {
|
||||
Throwable exc = (isOpen()) ? null : new ClosedChannelException();
|
||||
if (handler == null)
|
||||
return CompletedFuture.withResult(0, exc);
|
||||
Invoker.invokeIndirectly(handler, attachment, 0, exc, executor);
|
||||
return null;
|
||||
}
|
||||
|
||||
final PendingFuture<Integer,A> result = (handler == null) ?
|
||||
new PendingFuture<Integer,A>(this) : null;
|
||||
Runnable task = new Runnable() {
|
||||
public void run() {
|
||||
int n = 0;
|
||||
Throwable exc = null;
|
||||
|
||||
int ti = threads.add();
|
||||
try {
|
||||
begin();
|
||||
do {
|
||||
n = IOUtil.read(fdObj, dst, position, nd);
|
||||
} while ((n == IOStatus.INTERRUPTED) && isOpen());
|
||||
if (n < 0 && !isOpen())
|
||||
throw new AsynchronousCloseException();
|
||||
} catch (IOException x) {
|
||||
if (!isOpen())
|
||||
x = new AsynchronousCloseException();
|
||||
exc = x;
|
||||
} finally {
|
||||
end();
|
||||
threads.remove(ti);
|
||||
}
|
||||
if (handler == null) {
|
||||
result.setResult(n, exc);
|
||||
} else {
|
||||
Invoker.invokeUnchecked(handler, attachment, n, exc);
|
||||
}
|
||||
}
|
||||
};
|
||||
executor.execute(task);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
<A> Future<Integer> implWrite(final ByteBuffer src,
|
||||
final long position,
|
||||
final A attachment,
|
||||
final CompletionHandler<Integer,? super A> handler)
|
||||
{
|
||||
if (position < 0)
|
||||
throw new IllegalArgumentException("Negative position");
|
||||
if (!writing)
|
||||
throw new NonWritableChannelException();
|
||||
|
||||
// complete immediately if channel is closed or no bytes remaining
|
||||
if (!isOpen() || (src.remaining() == 0)) {
|
||||
Throwable exc = (isOpen()) ? null : new ClosedChannelException();
|
||||
if (handler == null)
|
||||
return CompletedFuture.withResult(0, exc);
|
||||
Invoker.invokeIndirectly(handler, attachment, 0, exc, executor);
|
||||
return null;
|
||||
}
|
||||
|
||||
final PendingFuture<Integer,A> result = (handler == null) ?
|
||||
new PendingFuture<Integer,A>(this) : null;
|
||||
Runnable task = new Runnable() {
|
||||
public void run() {
|
||||
int n = 0;
|
||||
Throwable exc = null;
|
||||
|
||||
int ti = threads.add();
|
||||
try {
|
||||
begin();
|
||||
do {
|
||||
n = IOUtil.write(fdObj, src, position, nd);
|
||||
} while ((n == IOStatus.INTERRUPTED) && isOpen());
|
||||
if (n < 0 && !isOpen())
|
||||
throw new AsynchronousCloseException();
|
||||
} catch (IOException x) {
|
||||
if (!isOpen())
|
||||
x = new AsynchronousCloseException();
|
||||
exc = x;
|
||||
} finally {
|
||||
end();
|
||||
threads.remove(ti);
|
||||
}
|
||||
if (handler == null) {
|
||||
result.setResult(n, exc);
|
||||
} else {
|
||||
Invoker.invokeUnchecked(handler, attachment, n, exc);
|
||||
}
|
||||
}
|
||||
};
|
||||
executor.execute(task);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
142
jdkSrc/jdk8/sun/nio/ch/SinkChannelImpl.java
Normal file
142
jdkSrc/jdk8/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;
|
||||
}
|
||||
}
|
||||
}
|
||||
457
jdkSrc/jdk8/sun/nio/ch/SocketAdaptor.java
Normal file
457
jdkSrc/jdk8/sun/nio/ch/SocketAdaptor.java
Normal file
@@ -0,0 +1,457 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2021, 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.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.SocketException;
|
||||
import java.net.SocketImpl;
|
||||
import java.net.SocketOption;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.StandardSocketOptions;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.IllegalBlockingModeException;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
// Make a socket channel look like a socket.
|
||||
//
|
||||
// The only aspects of java.net.Socket-hood that we don't attempt to emulate
|
||||
// here are the interrupted-I/O exceptions (which our Solaris implementations
|
||||
// attempt to support) and the sending of urgent data. Otherwise an adapted
|
||||
// socket should look enough like a real java.net.Socket to fool most of the
|
||||
// developers most of the time, right down to the exception message strings.
|
||||
//
|
||||
// The methods in this class are defined in exactly the same order as in
|
||||
// java.net.Socket so as to simplify tracking future changes to that class.
|
||||
//
|
||||
|
||||
class SocketAdaptor
|
||||
extends Socket
|
||||
{
|
||||
|
||||
// The channel being adapted
|
||||
private final SocketChannelImpl sc;
|
||||
|
||||
// Timeout "option" value for reads
|
||||
private volatile int timeout = 0;
|
||||
|
||||
private SocketAdaptor(SocketChannelImpl sc) throws SocketException {
|
||||
super((SocketImpl) null);
|
||||
this.sc = sc;
|
||||
}
|
||||
|
||||
public static Socket create(SocketChannelImpl sc) {
|
||||
try {
|
||||
return new SocketAdaptor(sc);
|
||||
} catch (SocketException e) {
|
||||
throw new InternalError("Should not reach here");
|
||||
}
|
||||
}
|
||||
|
||||
public SocketChannel getChannel() {
|
||||
return sc;
|
||||
}
|
||||
|
||||
// Override this method just to protect against changes in the superclass
|
||||
//
|
||||
public void connect(SocketAddress remote) throws IOException {
|
||||
connect(remote, 0);
|
||||
}
|
||||
|
||||
public void connect(SocketAddress remote, int timeout) throws IOException {
|
||||
if (remote == null)
|
||||
throw new IllegalArgumentException("connect: The address can't be null");
|
||||
if (timeout < 0)
|
||||
throw new IllegalArgumentException("connect: timeout can't be negative");
|
||||
|
||||
synchronized (sc.blockingLock()) {
|
||||
if (!sc.isBlocking())
|
||||
throw new IllegalBlockingModeException();
|
||||
|
||||
try {
|
||||
if (timeout == 0) {
|
||||
sc.connect(remote);
|
||||
return;
|
||||
}
|
||||
|
||||
sc.configureBlocking(false);
|
||||
try {
|
||||
if (sc.connect(remote))
|
||||
return;
|
||||
long to = timeout;
|
||||
for (;;) {
|
||||
if (!sc.isOpen())
|
||||
throw new ClosedChannelException();
|
||||
long st = System.currentTimeMillis();
|
||||
|
||||
int result = sc.poll(Net.POLLCONN, to);
|
||||
if (result > 0 && sc.finishConnect())
|
||||
break;
|
||||
to -= System.currentTimeMillis() - st;
|
||||
if (to <= 0) {
|
||||
try {
|
||||
sc.close();
|
||||
} catch (IOException x) { }
|
||||
throw new SocketTimeoutException();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
sc.configureBlocking(true);
|
||||
} catch (ClosedChannelException e) { }
|
||||
}
|
||||
|
||||
} catch (Exception x) {
|
||||
Net.translateException(x, true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void bind(SocketAddress local) throws IOException {
|
||||
try {
|
||||
sc.bind(local);
|
||||
} catch (Exception x) {
|
||||
Net.translateException(x);
|
||||
}
|
||||
}
|
||||
|
||||
public InetAddress getInetAddress() {
|
||||
SocketAddress remote = sc.remoteAddress();
|
||||
if (remote == null) {
|
||||
return null;
|
||||
} else {
|
||||
return ((InetSocketAddress)remote).getAddress();
|
||||
}
|
||||
}
|
||||
|
||||
public InetAddress getLocalAddress() {
|
||||
if (sc.isOpen()) {
|
||||
InetSocketAddress local = sc.localAddress();
|
||||
if (local != null) {
|
||||
return Net.getRevealedLocalAddress(local).getAddress();
|
||||
}
|
||||
}
|
||||
return new InetSocketAddress(0).getAddress();
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
SocketAddress remote = sc.remoteAddress();
|
||||
if (remote == null) {
|
||||
return 0;
|
||||
} else {
|
||||
return ((InetSocketAddress)remote).getPort();
|
||||
}
|
||||
}
|
||||
|
||||
public int getLocalPort() {
|
||||
SocketAddress local = sc.localAddress();
|
||||
if (local == null) {
|
||||
return -1;
|
||||
} else {
|
||||
return ((InetSocketAddress)local).getPort();
|
||||
}
|
||||
}
|
||||
|
||||
private class SocketInputStream
|
||||
extends ChannelInputStream
|
||||
{
|
||||
private SocketInputStream() {
|
||||
super(sc);
|
||||
}
|
||||
|
||||
protected int read(ByteBuffer bb)
|
||||
throws IOException
|
||||
{
|
||||
synchronized (sc.blockingLock()) {
|
||||
if (!sc.isOpen()) {
|
||||
throw new ClosedChannelException();
|
||||
}
|
||||
if (!sc.isBlocking())
|
||||
throw new IllegalBlockingModeException();
|
||||
|
||||
if (timeout == 0)
|
||||
return sc.read(bb);
|
||||
|
||||
sc.configureBlocking(false);
|
||||
try {
|
||||
int n;
|
||||
if ((n = sc.read(bb)) != 0)
|
||||
return n;
|
||||
long to = timeout;
|
||||
for (;;) {
|
||||
if (!sc.isOpen())
|
||||
throw new ClosedChannelException();
|
||||
long st = System.currentTimeMillis();
|
||||
int result = sc.poll(Net.POLLIN, to);
|
||||
if (result > 0) {
|
||||
if ((n = sc.read(bb)) != 0)
|
||||
return n;
|
||||
}
|
||||
to -= System.currentTimeMillis() - st;
|
||||
if (to <= 0)
|
||||
throw new SocketTimeoutException();
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
sc.configureBlocking(true);
|
||||
} catch (ClosedChannelException e) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private InputStream socketInputStream = null;
|
||||
|
||||
public InputStream getInputStream() throws IOException {
|
||||
if (!sc.isOpen())
|
||||
throw new SocketException("Socket is closed");
|
||||
if (!sc.isConnected())
|
||||
throw new SocketException("Socket is not connected");
|
||||
if (!sc.isInputOpen())
|
||||
throw new SocketException("Socket input is shutdown");
|
||||
if (socketInputStream == null) {
|
||||
try {
|
||||
socketInputStream = AccessController.doPrivileged(
|
||||
new PrivilegedExceptionAction<InputStream>() {
|
||||
public InputStream run() throws IOException {
|
||||
return new SocketInputStream();
|
||||
}
|
||||
});
|
||||
} catch (java.security.PrivilegedActionException e) {
|
||||
throw (IOException)e.getException();
|
||||
}
|
||||
}
|
||||
return socketInputStream;
|
||||
}
|
||||
|
||||
public OutputStream getOutputStream() throws IOException {
|
||||
if (!sc.isOpen())
|
||||
throw new SocketException("Socket is closed");
|
||||
if (!sc.isConnected())
|
||||
throw new SocketException("Socket is not connected");
|
||||
if (!sc.isOutputOpen())
|
||||
throw new SocketException("Socket output is shutdown");
|
||||
OutputStream os = null;
|
||||
try {
|
||||
os = AccessController.doPrivileged(
|
||||
new PrivilegedExceptionAction<OutputStream>() {
|
||||
public OutputStream run() throws IOException {
|
||||
return Channels.newOutputStream(sc);
|
||||
}
|
||||
});
|
||||
} catch (java.security.PrivilegedActionException e) {
|
||||
throw (IOException)e.getException();
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
private void setBooleanOption(SocketOption<Boolean> name, boolean value)
|
||||
throws SocketException
|
||||
{
|
||||
try {
|
||||
sc.setOption(name, value);
|
||||
} catch (IOException x) {
|
||||
Net.translateToSocketException(x);
|
||||
}
|
||||
}
|
||||
|
||||
private void setIntOption(SocketOption<Integer> name, int value)
|
||||
throws SocketException
|
||||
{
|
||||
try {
|
||||
sc.setOption(name, value);
|
||||
} catch (IOException x) {
|
||||
Net.translateToSocketException(x);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean getBooleanOption(SocketOption<Boolean> name) throws SocketException {
|
||||
try {
|
||||
return sc.getOption(name).booleanValue();
|
||||
} catch (IOException x) {
|
||||
Net.translateToSocketException(x);
|
||||
return false; // keep compiler happy
|
||||
}
|
||||
}
|
||||
|
||||
private int getIntOption(SocketOption<Integer> name) throws SocketException {
|
||||
try {
|
||||
return sc.getOption(name).intValue();
|
||||
} catch (IOException x) {
|
||||
Net.translateToSocketException(x);
|
||||
return -1; // keep compiler happy
|
||||
}
|
||||
}
|
||||
|
||||
public void setTcpNoDelay(boolean on) throws SocketException {
|
||||
setBooleanOption(StandardSocketOptions.TCP_NODELAY, on);
|
||||
}
|
||||
|
||||
public boolean getTcpNoDelay() throws SocketException {
|
||||
return getBooleanOption(StandardSocketOptions.TCP_NODELAY);
|
||||
}
|
||||
|
||||
public void setSoLinger(boolean on, int linger) throws SocketException {
|
||||
if (!on)
|
||||
linger = -1;
|
||||
setIntOption(StandardSocketOptions.SO_LINGER, linger);
|
||||
}
|
||||
|
||||
public int getSoLinger() throws SocketException {
|
||||
return getIntOption(StandardSocketOptions.SO_LINGER);
|
||||
}
|
||||
|
||||
public void sendUrgentData(int data) throws IOException {
|
||||
int n = sc.sendOutOfBandData((byte) data);
|
||||
if (n == 0)
|
||||
throw new IOException("Socket buffer full");
|
||||
}
|
||||
|
||||
public void setOOBInline(boolean on) throws SocketException {
|
||||
setBooleanOption(ExtendedSocketOption.SO_OOBINLINE, on);
|
||||
}
|
||||
|
||||
public boolean getOOBInline() throws SocketException {
|
||||
return getBooleanOption(ExtendedSocketOption.SO_OOBINLINE);
|
||||
}
|
||||
|
||||
public void setSoTimeout(int timeout) throws SocketException {
|
||||
if (timeout < 0)
|
||||
throw new IllegalArgumentException("timeout can't be negative");
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
public int getSoTimeout() throws SocketException {
|
||||
return timeout;
|
||||
}
|
||||
|
||||
public void setSendBufferSize(int size) throws SocketException {
|
||||
// size 0 valid for SocketChannel, invalid for Socket
|
||||
if (size <= 0)
|
||||
throw new IllegalArgumentException("Invalid send size");
|
||||
setIntOption(StandardSocketOptions.SO_SNDBUF, size);
|
||||
}
|
||||
|
||||
public int getSendBufferSize() throws SocketException {
|
||||
return getIntOption(StandardSocketOptions.SO_SNDBUF);
|
||||
}
|
||||
|
||||
public void setReceiveBufferSize(int size) throws SocketException {
|
||||
// size 0 valid for SocketChannel, invalid for Socket
|
||||
if (size <= 0)
|
||||
throw new IllegalArgumentException("Invalid receive size");
|
||||
setIntOption(StandardSocketOptions.SO_RCVBUF, size);
|
||||
}
|
||||
|
||||
public int getReceiveBufferSize() throws SocketException {
|
||||
return getIntOption(StandardSocketOptions.SO_RCVBUF);
|
||||
}
|
||||
|
||||
public void setKeepAlive(boolean on) throws SocketException {
|
||||
setBooleanOption(StandardSocketOptions.SO_KEEPALIVE, on);
|
||||
}
|
||||
|
||||
public boolean getKeepAlive() throws SocketException {
|
||||
return getBooleanOption(StandardSocketOptions.SO_KEEPALIVE);
|
||||
}
|
||||
|
||||
public void setTrafficClass(int tc) throws SocketException {
|
||||
setIntOption(StandardSocketOptions.IP_TOS, tc);
|
||||
}
|
||||
|
||||
public int getTrafficClass() throws SocketException {
|
||||
return getIntOption(StandardSocketOptions.IP_TOS);
|
||||
}
|
||||
|
||||
public void setReuseAddress(boolean on) throws SocketException {
|
||||
setBooleanOption(StandardSocketOptions.SO_REUSEADDR, on);
|
||||
}
|
||||
|
||||
public boolean getReuseAddress() throws SocketException {
|
||||
return getBooleanOption(StandardSocketOptions.SO_REUSEADDR);
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
sc.close();
|
||||
}
|
||||
|
||||
public void shutdownInput() throws IOException {
|
||||
try {
|
||||
sc.shutdownInput();
|
||||
} catch (Exception x) {
|
||||
Net.translateException(x);
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdownOutput() throws IOException {
|
||||
try {
|
||||
sc.shutdownOutput();
|
||||
} catch (Exception x) {
|
||||
Net.translateException(x);
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (sc.isConnected())
|
||||
return "Socket[addr=" + getInetAddress() +
|
||||
",port=" + getPort() +
|
||||
",localport=" + getLocalPort() + "]";
|
||||
return "Socket[unconnected]";
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
return sc.isConnected();
|
||||
}
|
||||
|
||||
public boolean isBound() {
|
||||
return sc.localAddress() != null;
|
||||
}
|
||||
|
||||
public boolean isClosed() {
|
||||
return !sc.isOpen();
|
||||
}
|
||||
|
||||
public boolean isInputShutdown() {
|
||||
return !sc.isInputOpen();
|
||||
}
|
||||
|
||||
public boolean isOutputShutdown() {
|
||||
return !sc.isOutputOpen();
|
||||
}
|
||||
|
||||
}
|
||||
1038
jdkSrc/jdk8/sun/nio/ch/SocketChannelImpl.java
Normal file
1038
jdkSrc/jdk8/sun/nio/ch/SocketChannelImpl.java
Normal file
File diff suppressed because it is too large
Load Diff
82
jdkSrc/jdk8/sun/nio/ch/SocketDispatcher.java
Normal file
82
jdkSrc/jdk8/sun/nio/ch/SocketDispatcher.java
Normal file
@@ -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;
|
||||
}
|
||||
115
jdkSrc/jdk8/sun/nio/ch/SocketOptionRegistry.java
Normal file
115
jdkSrc/jdk8/sun/nio/ch/SocketOptionRegistry.java
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 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.
|
||||
*
|
||||
*/
|
||||
// AUTOMATICALLY GENERATED FILE - DO NOT EDIT
|
||||
|
||||
package sun.nio.ch;
|
||||
import java.net.SocketOption;
|
||||
import java.net.StandardSocketOptions;
|
||||
import java.net.ProtocolFamily;
|
||||
import java.net.StandardProtocolFamily;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
class SocketOptionRegistry {
|
||||
|
||||
private SocketOptionRegistry() { }
|
||||
|
||||
private static class RegistryKey {
|
||||
private final SocketOption<?> name;
|
||||
private final ProtocolFamily family;
|
||||
RegistryKey(SocketOption<?> name, ProtocolFamily family) {
|
||||
this.name = name;
|
||||
this.family = family;
|
||||
}
|
||||
public int hashCode() {
|
||||
return name.hashCode() + family.hashCode();
|
||||
}
|
||||
public boolean equals(Object ob) {
|
||||
if (ob == null) return false;
|
||||
if (!(ob instanceof RegistryKey)) return false;
|
||||
RegistryKey other = (RegistryKey)ob;
|
||||
if (this.name != other.name) return false;
|
||||
if (this.family != other.family) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static class LazyInitialization {
|
||||
|
||||
static final Map<RegistryKey,OptionKey> options = options();
|
||||
|
||||
private static Map<RegistryKey,OptionKey> options() {
|
||||
Map<RegistryKey,OptionKey> map =
|
||||
new HashMap<RegistryKey,OptionKey>();
|
||||
map.put(new RegistryKey(StandardSocketOptions.SO_BROADCAST,
|
||||
Net.UNSPEC), new OptionKey(0xffff, 0x0020));
|
||||
map.put(new RegistryKey(StandardSocketOptions.SO_KEEPALIVE,
|
||||
Net.UNSPEC), new OptionKey(0xffff, 0x0008));
|
||||
map.put(new RegistryKey(StandardSocketOptions.SO_LINGER,
|
||||
Net.UNSPEC), new OptionKey(0xffff, 0x0080));
|
||||
map.put(new RegistryKey(StandardSocketOptions.SO_SNDBUF,
|
||||
Net.UNSPEC), new OptionKey(0xffff, 0x1001));
|
||||
map.put(new RegistryKey(StandardSocketOptions.SO_RCVBUF,
|
||||
Net.UNSPEC), new OptionKey(0xffff, 0x1002));
|
||||
map.put(new RegistryKey(StandardSocketOptions.SO_REUSEADDR,
|
||||
Net.UNSPEC), new OptionKey(0xffff, 0x0004));
|
||||
|
||||
map.put(new RegistryKey(StandardSocketOptions.TCP_NODELAY,
|
||||
Net.UNSPEC), new OptionKey(6, 0x0001));
|
||||
|
||||
|
||||
map.put(new RegistryKey(StandardSocketOptions.IP_TOS,
|
||||
StandardProtocolFamily.INET), new OptionKey(0, 3));
|
||||
map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_IF,
|
||||
StandardProtocolFamily.INET), new OptionKey(0, 9));
|
||||
map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_TTL,
|
||||
StandardProtocolFamily.INET), new OptionKey(0, 10));
|
||||
map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_LOOP,
|
||||
StandardProtocolFamily.INET), new OptionKey(0, 11));
|
||||
|
||||
|
||||
|
||||
map.put(new RegistryKey(StandardSocketOptions.IP_TOS,
|
||||
StandardProtocolFamily.INET6), new OptionKey(41, 39));
|
||||
map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_IF,
|
||||
StandardProtocolFamily.INET6), new OptionKey(41, 9));
|
||||
map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_TTL,
|
||||
StandardProtocolFamily.INET6), new OptionKey(41, 10));
|
||||
map.put(new RegistryKey(StandardSocketOptions.IP_MULTICAST_LOOP,
|
||||
StandardProtocolFamily.INET6), new OptionKey(41, 11));
|
||||
|
||||
|
||||
map.put(new RegistryKey(ExtendedSocketOption.SO_OOBINLINE,
|
||||
Net.UNSPEC), new OptionKey(0xffff, 0x0100));
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
public static OptionKey findOption(SocketOption<?> name, ProtocolFamily family) {
|
||||
RegistryKey key = new RegistryKey(name, family);
|
||||
return LazyInitialization.options.get(key);
|
||||
}
|
||||
}
|
||||
142
jdkSrc/jdk8/sun/nio/ch/SourceChannelImpl.java
Normal file
142
jdkSrc/jdk8/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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
180
jdkSrc/jdk8/sun/nio/ch/ThreadPool.java
Normal file
180
jdkSrc/jdk8/sun/nio/ch/ThreadPool.java
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 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;
|
||||
|
||||
import java.util.concurrent.*;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
import sun.security.action.GetIntegerAction;
|
||||
|
||||
/**
|
||||
* Encapsulates a thread pool associated with a channel group.
|
||||
*/
|
||||
|
||||
public class ThreadPool {
|
||||
private static final String DEFAULT_THREAD_POOL_THREAD_FACTORY =
|
||||
"java.nio.channels.DefaultThreadPool.threadFactory";
|
||||
private static final String DEFAULT_THREAD_POOL_INITIAL_SIZE =
|
||||
"java.nio.channels.DefaultThreadPool.initialSize";
|
||||
|
||||
private final ExecutorService executor;
|
||||
|
||||
// indicates if thread pool is fixed size
|
||||
private final boolean isFixed;
|
||||
|
||||
// indicates the pool size (for a fixed thread pool configuratin this is
|
||||
// the maximum pool size; for other thread pools it is the initial size)
|
||||
private final int poolSize;
|
||||
|
||||
private ThreadPool(ExecutorService executor,
|
||||
boolean isFixed,
|
||||
int poolSize)
|
||||
{
|
||||
this.executor = executor;
|
||||
this.isFixed = isFixed;
|
||||
this.poolSize = poolSize;
|
||||
}
|
||||
|
||||
ExecutorService executor() {
|
||||
return executor;
|
||||
}
|
||||
|
||||
boolean isFixedThreadPool() {
|
||||
return isFixed;
|
||||
}
|
||||
|
||||
int poolSize() {
|
||||
return poolSize;
|
||||
}
|
||||
|
||||
static ThreadFactory defaultThreadFactory() {
|
||||
if (System.getSecurityManager() == null) {
|
||||
return (Runnable r) -> {
|
||||
Thread t = new Thread(r);
|
||||
t.setDaemon(true);
|
||||
return t;
|
||||
};
|
||||
} else {
|
||||
return (Runnable r) -> {
|
||||
PrivilegedAction<Thread> action = () -> {
|
||||
Thread t = new sun.misc.InnocuousThread(r);
|
||||
t.setDaemon(true);
|
||||
return t;
|
||||
};
|
||||
return AccessController.doPrivileged(action);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private static class DefaultThreadPoolHolder {
|
||||
final static ThreadPool defaultThreadPool = createDefault();
|
||||
}
|
||||
|
||||
// return the default (system-wide) thread pool
|
||||
static ThreadPool getDefault() {
|
||||
return DefaultThreadPoolHolder.defaultThreadPool;
|
||||
}
|
||||
|
||||
// create thread using default settings (configured by system properties)
|
||||
static ThreadPool createDefault() {
|
||||
// default the number of fixed threads to the hardware core count
|
||||
int initialSize = getDefaultThreadPoolInitialSize();
|
||||
if (initialSize < 0)
|
||||
initialSize = Runtime.getRuntime().availableProcessors();
|
||||
// default to thread factory that creates daemon threads
|
||||
ThreadFactory threadFactory = getDefaultThreadPoolThreadFactory();
|
||||
if (threadFactory == null)
|
||||
threadFactory = defaultThreadFactory();
|
||||
// create thread pool
|
||||
ExecutorService executor = Executors.newCachedThreadPool(threadFactory);
|
||||
return new ThreadPool(executor, false, initialSize);
|
||||
}
|
||||
|
||||
// create using given parameters
|
||||
static ThreadPool create(int nThreads, ThreadFactory factory) {
|
||||
if (nThreads <= 0)
|
||||
throw new IllegalArgumentException("'nThreads' must be > 0");
|
||||
ExecutorService executor = Executors.newFixedThreadPool(nThreads, factory);
|
||||
return new ThreadPool(executor, true, nThreads);
|
||||
}
|
||||
|
||||
// wrap a user-supplied executor
|
||||
public static ThreadPool wrap(ExecutorService executor, int initialSize) {
|
||||
if (executor == null)
|
||||
throw new NullPointerException("'executor' is null");
|
||||
// attempt to check if cached thread pool
|
||||
if (executor instanceof ThreadPoolExecutor) {
|
||||
int max = ((ThreadPoolExecutor)executor).getMaximumPoolSize();
|
||||
if (max == Integer.MAX_VALUE) {
|
||||
if (initialSize < 0) {
|
||||
initialSize = Runtime.getRuntime().availableProcessors();
|
||||
} else {
|
||||
// not a cached thread pool so ignore initial size
|
||||
initialSize = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// some other type of thread pool
|
||||
if (initialSize < 0)
|
||||
initialSize = 0;
|
||||
}
|
||||
return new ThreadPool(executor, false, initialSize);
|
||||
}
|
||||
|
||||
private static int getDefaultThreadPoolInitialSize() {
|
||||
String propValue = AccessController.doPrivileged(new
|
||||
GetPropertyAction(DEFAULT_THREAD_POOL_INITIAL_SIZE));
|
||||
if (propValue != null) {
|
||||
try {
|
||||
return Integer.parseInt(propValue);
|
||||
} catch (NumberFormatException x) {
|
||||
throw new Error("Value of property '" + DEFAULT_THREAD_POOL_INITIAL_SIZE +
|
||||
"' is invalid: " + x);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static ThreadFactory getDefaultThreadPoolThreadFactory() {
|
||||
String propValue = AccessController.doPrivileged(new
|
||||
GetPropertyAction(DEFAULT_THREAD_POOL_THREAD_FACTORY));
|
||||
if (propValue != null) {
|
||||
try {
|
||||
Class<?> c = Class
|
||||
.forName(propValue, true, ClassLoader.getSystemClassLoader());
|
||||
return ((ThreadFactory)c.newInstance());
|
||||
} catch (ClassNotFoundException x) {
|
||||
throw new Error(x);
|
||||
} catch (InstantiationException x) {
|
||||
throw new Error(x);
|
||||
} catch (IllegalAccessException x) {
|
||||
throw new Error(x);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
491
jdkSrc/jdk8/sun/nio/ch/Util.java
Normal file
491
jdkSrc/jdk8/sun/nio/ch/Util.java
Normal file
@@ -0,0 +1,491 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 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.lang.ref.SoftReference;
|
||||
import java.lang.reflect.*;
|
||||
import java.io.IOException;
|
||||
import java.io.FileDescriptor;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.nio.channels.*;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.*;
|
||||
import jdk.internal.misc.TerminatingThreadLocal;
|
||||
import sun.misc.Unsafe;
|
||||
import sun.misc.Cleaner;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
|
||||
public class Util {
|
||||
|
||||
// -- Caches --
|
||||
|
||||
// The number of temp buffers in our pool
|
||||
private static final int TEMP_BUF_POOL_SIZE = IOUtil.IOV_MAX;
|
||||
|
||||
// The max size allowed for a cached temp buffer, in bytes
|
||||
private static final long MAX_CACHED_BUFFER_SIZE = getMaxCachedBufferSize();
|
||||
|
||||
// Per-thread cache of temporary direct buffers
|
||||
private static ThreadLocal<BufferCache> bufferCache = new TerminatingThreadLocal<BufferCache>() {
|
||||
@Override
|
||||
protected BufferCache initialValue() {
|
||||
return new BufferCache();
|
||||
}
|
||||
@Override
|
||||
protected void threadTerminated(BufferCache cache) { // will never be null
|
||||
while (!cache.isEmpty()) {
|
||||
ByteBuffer bb = cache.removeFirst();
|
||||
free(bb);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the max size allowed for a cached temp buffers, in
|
||||
* bytes. It defaults to Long.MAX_VALUE. It can be set with the
|
||||
* jdk.nio.maxCachedBufferSize property. Even though
|
||||
* ByteBuffer.capacity() returns an int, we're using a long here
|
||||
* for potential future-proofing.
|
||||
*/
|
||||
private static long getMaxCachedBufferSize() {
|
||||
String s = java.security.AccessController.doPrivileged(
|
||||
new PrivilegedAction<String>() {
|
||||
@Override
|
||||
public String run() {
|
||||
return System.getProperty("jdk.nio.maxCachedBufferSize");
|
||||
}
|
||||
});
|
||||
if (s != null) {
|
||||
try {
|
||||
long m = Long.parseLong(s);
|
||||
if (m >= 0) {
|
||||
return m;
|
||||
} else {
|
||||
// if it's negative, ignore the system property
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
// if the string is not well formed, ignore the system property
|
||||
}
|
||||
}
|
||||
return Long.MAX_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a buffer of this size is too large to be
|
||||
* added to the buffer cache, false otherwise.
|
||||
*/
|
||||
private static boolean isBufferTooLarge(int size) {
|
||||
return size > MAX_CACHED_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the buffer is too large to be added to the
|
||||
* buffer cache, false otherwise.
|
||||
*/
|
||||
private static boolean isBufferTooLarge(ByteBuffer buf) {
|
||||
return isBufferTooLarge(buf.capacity());
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple cache of direct buffers.
|
||||
*/
|
||||
private static class BufferCache {
|
||||
// the array of buffers
|
||||
private ByteBuffer[] buffers;
|
||||
|
||||
// the number of buffers in the cache
|
||||
private int count;
|
||||
|
||||
// the index of the first valid buffer (undefined if count == 0)
|
||||
private int start;
|
||||
|
||||
private int next(int i) {
|
||||
return (i + 1) % TEMP_BUF_POOL_SIZE;
|
||||
}
|
||||
|
||||
BufferCache() {
|
||||
buffers = new ByteBuffer[TEMP_BUF_POOL_SIZE];
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes and returns a buffer from the cache of at least the given
|
||||
* size (or null if no suitable buffer is found).
|
||||
*/
|
||||
ByteBuffer get(int size) {
|
||||
// Don't call this if the buffer would be too large.
|
||||
assert !isBufferTooLarge(size);
|
||||
|
||||
if (count == 0)
|
||||
return null; // cache is empty
|
||||
|
||||
ByteBuffer[] buffers = this.buffers;
|
||||
|
||||
// search for suitable buffer (often the first buffer will do)
|
||||
ByteBuffer buf = buffers[start];
|
||||
if (buf.capacity() < size) {
|
||||
buf = null;
|
||||
int i = start;
|
||||
while ((i = next(i)) != start) {
|
||||
ByteBuffer bb = buffers[i];
|
||||
if (bb == null)
|
||||
break;
|
||||
if (bb.capacity() >= size) {
|
||||
buf = bb;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (buf == null)
|
||||
return null;
|
||||
// move first element to here to avoid re-packing
|
||||
buffers[i] = buffers[start];
|
||||
}
|
||||
|
||||
// remove first element
|
||||
buffers[start] = null;
|
||||
start = next(start);
|
||||
count--;
|
||||
|
||||
// prepare the buffer and return it
|
||||
buf.rewind();
|
||||
buf.limit(size);
|
||||
return buf;
|
||||
}
|
||||
|
||||
boolean offerFirst(ByteBuffer buf) {
|
||||
// Don't call this if the buffer is too large.
|
||||
assert !isBufferTooLarge(buf);
|
||||
|
||||
if (count >= TEMP_BUF_POOL_SIZE) {
|
||||
return false;
|
||||
} else {
|
||||
start = (start + TEMP_BUF_POOL_SIZE - 1) % TEMP_BUF_POOL_SIZE;
|
||||
buffers[start] = buf;
|
||||
count++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
boolean offerLast(ByteBuffer buf) {
|
||||
// Don't call this if the buffer is too large.
|
||||
assert !isBufferTooLarge(buf);
|
||||
|
||||
if (count >= TEMP_BUF_POOL_SIZE) {
|
||||
return false;
|
||||
} else {
|
||||
int next = (start + count) % TEMP_BUF_POOL_SIZE;
|
||||
buffers[next] = buf;
|
||||
count++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
boolean isEmpty() {
|
||||
return count == 0;
|
||||
}
|
||||
|
||||
ByteBuffer removeFirst() {
|
||||
assert count > 0;
|
||||
ByteBuffer buf = buffers[start];
|
||||
buffers[start] = null;
|
||||
start = next(start);
|
||||
count--;
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a temporary buffer of at least the given size
|
||||
*/
|
||||
public static ByteBuffer getTemporaryDirectBuffer(int size) {
|
||||
// If a buffer of this size is too large for the cache, there
|
||||
// should not be a buffer in the cache that is at least as
|
||||
// large. So we'll just create a new one. Also, we don't have
|
||||
// to remove the buffer from the cache (as this method does
|
||||
// below) given that we won't put the new buffer in the cache.
|
||||
if (isBufferTooLarge(size)) {
|
||||
return ByteBuffer.allocateDirect(size);
|
||||
}
|
||||
|
||||
BufferCache cache = bufferCache.get();
|
||||
ByteBuffer buf = cache.get(size);
|
||||
if (buf != null) {
|
||||
return buf;
|
||||
} else {
|
||||
// No suitable buffer in the cache so we need to allocate a new
|
||||
// one. To avoid the cache growing then we remove the first
|
||||
// buffer from the cache and free it.
|
||||
if (!cache.isEmpty()) {
|
||||
buf = cache.removeFirst();
|
||||
free(buf);
|
||||
}
|
||||
return ByteBuffer.allocateDirect(size);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases a temporary buffer by returning to the cache or freeing it.
|
||||
*/
|
||||
public static void releaseTemporaryDirectBuffer(ByteBuffer buf) {
|
||||
offerFirstTemporaryDirectBuffer(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases a temporary buffer by returning to the cache or freeing it. If
|
||||
* returning to the cache then insert it at the start so that it is
|
||||
* likely to be returned by a subsequent call to getTemporaryDirectBuffer.
|
||||
*/
|
||||
static void offerFirstTemporaryDirectBuffer(ByteBuffer buf) {
|
||||
// If the buffer is too large for the cache we don't have to
|
||||
// check the cache. We'll just free it.
|
||||
if (isBufferTooLarge(buf)) {
|
||||
free(buf);
|
||||
return;
|
||||
}
|
||||
|
||||
assert buf != null;
|
||||
BufferCache cache = bufferCache.get();
|
||||
if (!cache.offerFirst(buf)) {
|
||||
// cache is full
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases a temporary buffer by returning to the cache or freeing it. If
|
||||
* returning to the cache then insert it at the end. This makes it
|
||||
* suitable for scatter/gather operations where the buffers are returned to
|
||||
* cache in same order that they were obtained.
|
||||
*/
|
||||
static void offerLastTemporaryDirectBuffer(ByteBuffer buf) {
|
||||
// If the buffer is too large for the cache we don't have to
|
||||
// check the cache. We'll just free it.
|
||||
if (isBufferTooLarge(buf)) {
|
||||
free(buf);
|
||||
return;
|
||||
}
|
||||
|
||||
assert buf != null;
|
||||
BufferCache cache = bufferCache.get();
|
||||
if (!cache.offerLast(buf)) {
|
||||
// cache is full
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees the memory for the given direct buffer
|
||||
*/
|
||||
private static void free(ByteBuffer buf) {
|
||||
((DirectBuffer)buf).cleaner().clean();
|
||||
}
|
||||
|
||||
|
||||
// -- Random stuff --
|
||||
|
||||
static ByteBuffer[] subsequence(ByteBuffer[] bs, int offset, int length) {
|
||||
if ((offset == 0) && (length == bs.length))
|
||||
return bs;
|
||||
int n = length;
|
||||
ByteBuffer[] bs2 = new ByteBuffer[n];
|
||||
for (int i = 0; i < n; i++)
|
||||
bs2[i] = bs[offset + i];
|
||||
return bs2;
|
||||
}
|
||||
|
||||
static <E> Set<E> ungrowableSet(final Set<E> s) {
|
||||
return new Set<E>() {
|
||||
|
||||
public int size() { return s.size(); }
|
||||
public boolean isEmpty() { return s.isEmpty(); }
|
||||
public boolean contains(Object o) { return s.contains(o); }
|
||||
public Object[] toArray() { return s.toArray(); }
|
||||
public <T> T[] toArray(T[] a) { return s.toArray(a); }
|
||||
public String toString() { return s.toString(); }
|
||||
public Iterator<E> iterator() { return s.iterator(); }
|
||||
public boolean equals(Object o) { return s.equals(o); }
|
||||
public int hashCode() { return s.hashCode(); }
|
||||
public void clear() { s.clear(); }
|
||||
public boolean remove(Object o) { return s.remove(o); }
|
||||
|
||||
public boolean containsAll(Collection<?> coll) {
|
||||
return s.containsAll(coll);
|
||||
}
|
||||
public boolean removeAll(Collection<?> coll) {
|
||||
return s.removeAll(coll);
|
||||
}
|
||||
public boolean retainAll(Collection<?> coll) {
|
||||
return s.retainAll(coll);
|
||||
}
|
||||
|
||||
public boolean add(E o){
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
public boolean addAll(Collection<? extends E> coll) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// -- Unsafe access --
|
||||
|
||||
private static Unsafe unsafe = Unsafe.getUnsafe();
|
||||
|
||||
private static byte _get(long a) {
|
||||
return unsafe.getByte(a);
|
||||
}
|
||||
|
||||
private static void _put(long a, byte b) {
|
||||
unsafe.putByte(a, b);
|
||||
}
|
||||
|
||||
static void erase(ByteBuffer bb) {
|
||||
unsafe.setMemory(((DirectBuffer)bb).address(), bb.capacity(), (byte)0);
|
||||
}
|
||||
|
||||
static Unsafe unsafe() {
|
||||
return unsafe;
|
||||
}
|
||||
|
||||
private static int pageSize = -1;
|
||||
|
||||
static int pageSize() {
|
||||
if (pageSize == -1)
|
||||
pageSize = unsafe().pageSize();
|
||||
return pageSize;
|
||||
}
|
||||
|
||||
private static volatile Constructor<?> directByteBufferConstructor = null;
|
||||
|
||||
private static void initDBBConstructor() {
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
try {
|
||||
Class<?> cl = Class.forName("java.nio.DirectByteBuffer");
|
||||
Constructor<?> ctor = cl.getDeclaredConstructor(
|
||||
new Class<?>[] { int.class,
|
||||
long.class,
|
||||
FileDescriptor.class,
|
||||
Runnable.class });
|
||||
ctor.setAccessible(true);
|
||||
directByteBufferConstructor = ctor;
|
||||
} catch (ClassNotFoundException |
|
||||
NoSuchMethodException |
|
||||
IllegalArgumentException |
|
||||
ClassCastException x) {
|
||||
throw new InternalError(x);
|
||||
}
|
||||
return null;
|
||||
}});
|
||||
}
|
||||
|
||||
static MappedByteBuffer newMappedByteBuffer(int size, long addr,
|
||||
FileDescriptor fd,
|
||||
Runnable unmapper)
|
||||
{
|
||||
MappedByteBuffer dbb;
|
||||
if (directByteBufferConstructor == null)
|
||||
initDBBConstructor();
|
||||
try {
|
||||
dbb = (MappedByteBuffer)directByteBufferConstructor.newInstance(
|
||||
new Object[] { new Integer(size),
|
||||
new Long(addr),
|
||||
fd,
|
||||
unmapper });
|
||||
} catch (InstantiationException |
|
||||
IllegalAccessException |
|
||||
InvocationTargetException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
return dbb;
|
||||
}
|
||||
|
||||
private static volatile Constructor<?> directByteBufferRConstructor = null;
|
||||
|
||||
private static void initDBBRConstructor() {
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
try {
|
||||
Class<?> cl = Class.forName("java.nio.DirectByteBufferR");
|
||||
Constructor<?> ctor = cl.getDeclaredConstructor(
|
||||
new Class<?>[] { int.class,
|
||||
long.class,
|
||||
FileDescriptor.class,
|
||||
Runnable.class });
|
||||
ctor.setAccessible(true);
|
||||
directByteBufferRConstructor = ctor;
|
||||
} catch (ClassNotFoundException |
|
||||
NoSuchMethodException |
|
||||
IllegalArgumentException |
|
||||
ClassCastException x) {
|
||||
throw new InternalError(x);
|
||||
}
|
||||
return null;
|
||||
}});
|
||||
}
|
||||
|
||||
static MappedByteBuffer newMappedByteBufferR(int size, long addr,
|
||||
FileDescriptor fd,
|
||||
Runnable unmapper)
|
||||
{
|
||||
MappedByteBuffer dbb;
|
||||
if (directByteBufferRConstructor == null)
|
||||
initDBBRConstructor();
|
||||
try {
|
||||
dbb = (MappedByteBuffer)directByteBufferRConstructor.newInstance(
|
||||
new Object[] { new Integer(size),
|
||||
new Long(addr),
|
||||
fd,
|
||||
unmapper });
|
||||
} catch (InstantiationException |
|
||||
IllegalAccessException |
|
||||
InvocationTargetException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
return dbb;
|
||||
}
|
||||
|
||||
|
||||
// -- Bug compatibility --
|
||||
|
||||
private static volatile String bugLevel = null;
|
||||
|
||||
static boolean atBugLevel(String bl) { // package-private
|
||||
if (bugLevel == null) {
|
||||
if (!sun.misc.VM.isBooted())
|
||||
return false;
|
||||
String value = AccessController.doPrivileged(
|
||||
new GetPropertyAction("sun.nio.ch.bugLevel"));
|
||||
bugLevel = (value != null) ? value : "";
|
||||
}
|
||||
return bugLevel.equals(bl);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
757
jdkSrc/jdk8/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java
Normal file
757
jdkSrc/jdk8/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java
Normal file
@@ -0,0 +1,757 @@
|
||||
/*
|
||||
* 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 sun.misc.SharedSecrets;
|
||||
import sun.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
|
||||
if (Iocp.supportsThreadAgnosticIo()) {
|
||||
lockTask.run();
|
||||
} else {
|
||||
boolean executed = false;
|
||||
try {
|
||||
Invoker.invokeOnThreadInThreadPool(this, lockTask);
|
||||
executed = true;
|
||||
} finally {
|
||||
if (!executed) {
|
||||
// rollback
|
||||
removeFromFileLockTable(fli);
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
if (Iocp.supportsThreadAgnosticIo()) {
|
||||
readTask.run();
|
||||
} else {
|
||||
Invoker.invokeOnThreadInThreadPool(this, readTask);
|
||||
}
|
||||
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
|
||||
if (Iocp.supportsThreadAgnosticIo()) {
|
||||
writeTask.run();
|
||||
} else {
|
||||
Invoker.invokeOnThreadInThreadPool(this, writeTask);
|
||||
}
|
||||
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,369 @@
|
||||
/*
|
||||
* 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 sun.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
|
||||
if (Iocp.supportsThreadAgnosticIo()) {
|
||||
task.run();
|
||||
} else {
|
||||
Invoker.invokeOnThreadInThreadPool(this, task);
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
946
jdkSrc/jdk8/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java
Normal file
946
jdkSrc/jdk8/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java
Normal file
@@ -0,0 +1,946 @@
|
||||
/*
|
||||
* 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 sun.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
|
||||
if (Iocp.supportsThreadAgnosticIo()) {
|
||||
task.run();
|
||||
} else {
|
||||
Invoker.invokeOnThreadInThreadPool(this, task);
|
||||
}
|
||||
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
|
||||
if (Iocp.supportsThreadAgnosticIo()) {
|
||||
readTask.run();
|
||||
} else {
|
||||
Invoker.invokeOnThreadInThreadPool(this, readTask);
|
||||
}
|
||||
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 (can only be done from thread in thread pool)
|
||||
// initiate I/O
|
||||
if (Iocp.supportsThreadAgnosticIo()) {
|
||||
writeTask.run();
|
||||
} else {
|
||||
Invoker.invokeOnThreadInThreadPool(this, writeTask);
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
641
jdkSrc/jdk8/sun/nio/ch/WindowsSelectorImpl.java
Normal file
641
jdkSrc/jdk8/sun/nio/ch/WindowsSelectorImpl.java
Normal file
@@ -0,0 +1,641 @@
|
||||
/*
|
||||
* 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;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
/**
|
||||
* A multi-threaded implementation of Selector for Windows.
|
||||
*
|
||||
* @author Konstantin Kladko
|
||||
* @author Mark Reinhold
|
||||
*/
|
||||
|
||||
final class WindowsSelectorImpl extends SelectorImpl {
|
||||
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;
|
||||
}
|
||||
|
||||
// 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 final static int MAX_SELECTABLE_FDS = 1024;
|
||||
|
||||
// Size of FD_SET struct to allocate a buffer for it in SubSelector,
|
||||
// aligned to 8 bytes on 64-bit:
|
||||
// struct { unsigned int fd_count; SOCKET fd_array[MAX_SELECTABLE_FDS]; }.
|
||||
private static final long SIZEOF_FD_SET = dependsArch(
|
||||
4 + MAX_SELECTABLE_FDS * 4, // SOCKET = unsigned int
|
||||
4 + MAX_SELECTABLE_FDS * 8 + 4); // SOCKET = unsigned __int64
|
||||
|
||||
// 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 final static class FdMap extends HashMap<Integer, MapEntry> {
|
||||
static final long serialVersionUID = 0L;
|
||||
private MapEntry get(int desc) {
|
||||
return get(new Integer(desc));
|
||||
}
|
||||
private MapEntry put(SelectionKeyImpl ski) {
|
||||
return put(new Integer(ski.channel.getFDVal()), new MapEntry(ski));
|
||||
}
|
||||
private MapEntry remove(SelectionKeyImpl ski) {
|
||||
Integer fd = new Integer(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 final static 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 = false;
|
||||
|
||||
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];
|
||||
// Buffer for readfds, writefds and exceptfds structs that are passed
|
||||
// to native select().
|
||||
private final long fdsBuffer = unsafe.allocateMemory(SIZEOF_FD_SET * 6);
|
||||
|
||||
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, fdsBuffer);
|
||||
}
|
||||
|
||||
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, fdsBuffer);
|
||||
}
|
||||
|
||||
private native int poll0(long pollAddress, int numfds,
|
||||
int[] readFds, int[] writeFds, int[] exceptFds, long timeout, long fdsBuffer);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private void freeFDSetBuffer() {
|
||||
unsafe.freeMemory(fdsBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
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)) {
|
||||
subSelector.freeFDSetBuffer();
|
||||
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();
|
||||
subSelector.freeFDSetBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
46
jdkSrc/jdk8/sun/nio/ch/WindowsSelectorProvider.java
Normal file
46
jdkSrc/jdk8/sun/nio/ch/WindowsSelectorProvider.java
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
170
jdkSrc/jdk8/sun/nio/ch/sctp/MessageInfoImpl.java
Normal file
170
jdkSrc/jdk8/sun/nio/ch/sctp/MessageInfoImpl.java
Normal file
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 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.sctp;
|
||||
|
||||
import java.net.SocketAddress;
|
||||
import com.sun.nio.sctp.MessageInfo;
|
||||
import com.sun.nio.sctp.Association;
|
||||
|
||||
/**
|
||||
* An implementation of a MessageInfo.
|
||||
*/
|
||||
public class MessageInfoImpl extends MessageInfo {
|
||||
private final SocketAddress address;
|
||||
private final int bytes; /* 0 */
|
||||
|
||||
private Association association;
|
||||
private int assocId;
|
||||
private int streamNumber;
|
||||
private boolean complete = true;
|
||||
private boolean unordered; /* false */
|
||||
private long timeToLive; /* 0L */
|
||||
private int ppid; /* 0 */
|
||||
|
||||
public MessageInfoImpl(Association association,
|
||||
SocketAddress address,
|
||||
int streamNumber) {
|
||||
this.association = association;
|
||||
this.address = address;
|
||||
this.streamNumber = streamNumber;
|
||||
bytes = 0;
|
||||
}
|
||||
|
||||
/* Invoked from native */
|
||||
private MessageInfoImpl(int assocId,
|
||||
SocketAddress address,
|
||||
int bytes,
|
||||
int streamNumber,
|
||||
boolean complete,
|
||||
boolean unordered,
|
||||
int ppid) {
|
||||
this.assocId = assocId;
|
||||
this.address = address;
|
||||
this.bytes = bytes;
|
||||
this.streamNumber = streamNumber;
|
||||
this.complete = complete;
|
||||
this.unordered = unordered;
|
||||
this.ppid = ppid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Association association() {
|
||||
return association;
|
||||
}
|
||||
|
||||
/**
|
||||
* MessageInfoImpl instances created from native will need to have their
|
||||
* association set from the channel.
|
||||
*/
|
||||
void setAssociation(Association association) {
|
||||
this.association = association;
|
||||
}
|
||||
|
||||
int associationID() {
|
||||
return assocId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketAddress address() {
|
||||
return address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bytes() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int streamNumber() {
|
||||
return streamNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageInfo streamNumber(int streamNumber) {
|
||||
if (streamNumber < 0 || streamNumber > 65536)
|
||||
throw new IllegalArgumentException("Invalid stream number");
|
||||
|
||||
this.streamNumber = streamNumber;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int payloadProtocolID() {
|
||||
return ppid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageInfo payloadProtocolID(int ppid) {
|
||||
this.ppid = ppid;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isComplete() {
|
||||
return complete;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageInfo complete(boolean complete) {
|
||||
this.complete = complete;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnordered() {
|
||||
return unordered;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageInfo unordered(boolean unordered) {
|
||||
this.unordered = unordered;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long timeToLive() {
|
||||
return timeToLive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageInfo timeToLive(long millis) {
|
||||
timeToLive = millis;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(super.toString());
|
||||
sb.append( "[Address: ").append(address)
|
||||
.append(", Association: ").append(association)
|
||||
.append(", Assoc ID: ").append(assocId)
|
||||
.append(", Bytes: ").append(bytes)
|
||||
.append(", Stream Number: ").append(streamNumber)
|
||||
.append(", Complete: ").append(complete)
|
||||
.append(", isUnordered: ").append(unordered)
|
||||
.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
150
jdkSrc/jdk8/sun/nio/ch/sctp/SctpChannelImpl.java
Normal file
150
jdkSrc/jdk8/sun/nio/ch/sctp/SctpChannelImpl.java
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 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.sctp;
|
||||
|
||||
import java.net.SocketAddress;
|
||||
import java.net.InetAddress;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
import com.sun.nio.sctp.Association;
|
||||
import com.sun.nio.sctp.MessageInfo;
|
||||
import com.sun.nio.sctp.NotificationHandler;
|
||||
import com.sun.nio.sctp.SctpChannel;
|
||||
import com.sun.nio.sctp.SctpSocketOption;
|
||||
|
||||
/**
|
||||
* Unimplemented.
|
||||
*/
|
||||
public class SctpChannelImpl extends SctpChannel
|
||||
{
|
||||
private static final String message = "SCTP not supported on this platform";
|
||||
|
||||
public SctpChannelImpl(SelectorProvider provider) {
|
||||
super(provider);
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Association association() {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SctpChannel bind(SocketAddress local)
|
||||
throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SctpChannel bindAddress(InetAddress address)
|
||||
throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SctpChannel unbindAddress(InetAddress address)
|
||||
throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean connect(SocketAddress remote) throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean connect(SocketAddress remote, int maxOutStreams,
|
||||
int maxInStreams) throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnectionPending() {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean finishConnect() throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SocketAddress> getAllLocalAddresses()
|
||||
throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SocketAddress> getRemoteAddresses()
|
||||
throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SctpChannel shutdown() throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getOption(SctpSocketOption<T> name)
|
||||
throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> SctpChannel setOption(SctpSocketOption<T> name, T value)
|
||||
throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SctpSocketOption<?>> supportedOptions() {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> MessageInfo receive(ByteBuffer dst, T attachment,
|
||||
NotificationHandler<T> handler) throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int send(ByteBuffer src, MessageInfo messageInfo)
|
||||
throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void implConfigureBlocking(boolean block) throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void implCloseSelectableChannel() throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
}
|
||||
137
jdkSrc/jdk8/sun/nio/ch/sctp/SctpMultiChannelImpl.java
Normal file
137
jdkSrc/jdk8/sun/nio/ch/sctp/SctpMultiChannelImpl.java
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 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.sctp;
|
||||
|
||||
import java.net.SocketAddress;
|
||||
import java.net.InetAddress;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
import com.sun.nio.sctp.Association;
|
||||
import com.sun.nio.sctp.SctpChannel;
|
||||
import com.sun.nio.sctp.MessageInfo;
|
||||
import com.sun.nio.sctp.NotificationHandler;
|
||||
import com.sun.nio.sctp.SctpMultiChannel;
|
||||
import com.sun.nio.sctp.SctpSocketOption;
|
||||
|
||||
/**
|
||||
* Unimplemented.
|
||||
*/
|
||||
public class SctpMultiChannelImpl extends SctpMultiChannel
|
||||
{
|
||||
private static final String message = "SCTP not supported on this platform";
|
||||
|
||||
public SctpMultiChannelImpl(SelectorProvider provider) {
|
||||
super(provider);
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Association> associations() {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SctpMultiChannel bind(SocketAddress local,
|
||||
int backlog) throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SctpMultiChannel bindAddress(InetAddress address)
|
||||
throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SctpMultiChannel unbindAddress(InetAddress address)
|
||||
throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SocketAddress> getAllLocalAddresses()
|
||||
throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SocketAddress> getRemoteAddresses
|
||||
(Association association) throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SctpMultiChannel shutdown(Association association)
|
||||
throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getOption(SctpSocketOption<T> name,
|
||||
Association association) throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> SctpMultiChannel setOption(SctpSocketOption<T> name,
|
||||
T value, Association association) throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SctpSocketOption<?>> supportedOptions() {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> MessageInfo receive(ByteBuffer buffer, T attachment,
|
||||
NotificationHandler<T> handler) throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int send(ByteBuffer buffer, MessageInfo messageInfo)
|
||||
throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SctpChannel branch(Association association)
|
||||
throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void implConfigureBlocking(boolean block) throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void implCloseSelectableChannel() throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
}
|
||||
102
jdkSrc/jdk8/sun/nio/ch/sctp/SctpServerChannelImpl.java
Normal file
102
jdkSrc/jdk8/sun/nio/ch/sctp/SctpServerChannelImpl.java
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 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.sctp;
|
||||
|
||||
import java.net.SocketAddress;
|
||||
import java.net.InetAddress;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
import com.sun.nio.sctp.SctpChannel;
|
||||
import com.sun.nio.sctp.SctpServerChannel;
|
||||
import com.sun.nio.sctp.SctpSocketOption;
|
||||
|
||||
/**
|
||||
* Unimplemented.
|
||||
*/
|
||||
public class SctpServerChannelImpl extends SctpServerChannel
|
||||
{
|
||||
private static final String message = "SCTP not supported on this platform";
|
||||
|
||||
public SctpServerChannelImpl(SelectorProvider provider) {
|
||||
super(provider);
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SctpChannel accept() throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SctpServerChannel bind(SocketAddress local,
|
||||
int backlog) throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SctpServerChannel bindAddress(InetAddress address)
|
||||
throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SctpServerChannel unbindAddress(InetAddress address)
|
||||
throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SocketAddress> getAllLocalAddresses()
|
||||
throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getOption(SctpSocketOption<T> name) throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> SctpServerChannel setOption(SctpSocketOption<T> name,
|
||||
T value) throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SctpSocketOption<?>> supportedOptions() {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void implConfigureBlocking(boolean block) throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void implCloseSelectableChannel() throws IOException {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
}
|
||||
77
jdkSrc/jdk8/sun/nio/ch/sctp/SctpStdSocketOption.java
Normal file
77
jdkSrc/jdk8/sun/nio/ch/sctp/SctpStdSocketOption.java
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 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.sctp;
|
||||
|
||||
import com.sun.nio.sctp.SctpSocketOption;
|
||||
import java.lang.annotation.Native;
|
||||
|
||||
public class SctpStdSocketOption<T>
|
||||
implements SctpSocketOption<T>
|
||||
{
|
||||
/* for native mapping of int options */
|
||||
@Native public static final int SCTP_DISABLE_FRAGMENTS = 1;
|
||||
@Native public static final int SCTP_EXPLICIT_COMPLETE = 2;
|
||||
@Native public static final int SCTP_FRAGMENT_INTERLEAVE = 3;
|
||||
@Native public static final int SCTP_NODELAY = 4;
|
||||
@Native public static final int SO_SNDBUF = 5;
|
||||
@Native public static final int SO_RCVBUF = 6;
|
||||
@Native public static final int SO_LINGER = 7;
|
||||
|
||||
private final String name;
|
||||
private final Class<T> type;
|
||||
|
||||
/* for native mapping of int options */
|
||||
private int constValue;
|
||||
|
||||
public SctpStdSocketOption(String name, Class<T> type) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public SctpStdSocketOption(String name, Class<T> type, int constValue) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.constValue = constValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<T> type() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
int constValue() {
|
||||
return constValue;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user