feat(jdk8): move files to new folder to avoid resources compiled.

This commit is contained in:
2025-09-07 15:25:52 +08:00
parent 3f0047bf6f
commit 8c35cfb1c0
17415 changed files with 217 additions and 213 deletions

View 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);
}
}

View 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();
}
}

View 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;
}
}
}

View 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);
}
}

View 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);
}
}

View 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();
}
}

View 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();
}
}

View 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);
}

View 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();
}
}

View 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;
}
}

File diff suppressed because it is too large Load Diff

View 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;
}

View 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 {}
};
}

View File

@@ -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();
}
}

View 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();
}
}

View 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();
}

View 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(); }
};
}

File diff suppressed because it is too large Load Diff

View 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();
}

View 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;
}

View 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();
}
}

View 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;
}
}
}

View 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);
}
}
}
}
}

View 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();
}

View 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));
}
}

View 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();
}
}

View 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);
}
}

View 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);
}

View 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());
}
}
}

View 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;
}
}

View 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();
}
}

View 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();
}
}
}
}
}

View 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
}
}

View 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;
}
}

View 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) { }
}

View 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();
}
}

View 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();
}
}

View 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;
}
}

View 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;
}
}

View 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();
}
}

View 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;
}
}

View 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);
}
}

View 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();
}
}

View 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);
}
}
}

View 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);
}
}
}

View 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;
}

View 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;
}
}

View 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();
}

View 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);
}
}

View 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
}
}
}

View 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();
}
}

View 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;
}
}

View 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;
}
}
}

View 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();
}
}

File diff suppressed because it is too large Load Diff

View 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;
}

View 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);
}
}

View 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;
}
}
}

View 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;
}
}

View 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);
}
}

View File

@@ -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));
}
}

View 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();
}
}

View File

@@ -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();
}
}

View 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();
}
}

View 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();
}
}

View 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);
}
}

View 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();
}
}

View 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);
}
}

View 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);
}
}

View 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);
}
}

View 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;
}
}