Merged gcj-eclipse branch to trunk.
From-SVN: r120621
This commit is contained in:
@@ -55,8 +55,10 @@ import java.nio.channels.spi.SelectorProvider;
|
||||
* @author Michael Koch
|
||||
*/
|
||||
public final class DatagramChannelImpl extends DatagramChannel
|
||||
implements VMChannelOwner
|
||||
{
|
||||
private NIODatagramSocket socket;
|
||||
private VMChannel channel;
|
||||
|
||||
/**
|
||||
* Indicates whether this channel initiated whatever operation
|
||||
@@ -64,6 +66,16 @@ public final class DatagramChannelImpl extends DatagramChannel
|
||||
*/
|
||||
private boolean inChannelOperation;
|
||||
|
||||
protected DatagramChannelImpl (SelectorProvider provider)
|
||||
throws IOException
|
||||
{
|
||||
super (provider);
|
||||
socket = new NIODatagramSocket (new PlainDatagramSocketImpl(), this);
|
||||
channel = new VMChannel();
|
||||
channel.initSocket(false);
|
||||
configureBlocking(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether our datagram socket should ignore whether
|
||||
* we are set to non-blocking mode. Certain operations on our
|
||||
@@ -85,14 +97,6 @@ public final class DatagramChannelImpl extends DatagramChannel
|
||||
inChannelOperation = b;
|
||||
}
|
||||
|
||||
protected DatagramChannelImpl (SelectorProvider provider)
|
||||
throws IOException
|
||||
{
|
||||
super (provider);
|
||||
socket = new NIODatagramSocket (new PlainDatagramSocketImpl(), this);
|
||||
configureBlocking(true);
|
||||
}
|
||||
|
||||
public DatagramSocket socket ()
|
||||
{
|
||||
return socket;
|
||||
@@ -101,13 +105,13 @@ public final class DatagramChannelImpl extends DatagramChannel
|
||||
protected void implCloseSelectableChannel ()
|
||||
throws IOException
|
||||
{
|
||||
socket.close ();
|
||||
channel.close();
|
||||
}
|
||||
|
||||
protected void implConfigureBlocking (boolean blocking)
|
||||
throws IOException
|
||||
{
|
||||
socket.setSoTimeout (blocking ? 0 : NIOConstants.DEFAULT_TIMEOUT);
|
||||
channel.setBlocking(blocking);
|
||||
}
|
||||
|
||||
public DatagramChannel connect (SocketAddress remote)
|
||||
@@ -116,20 +120,34 @@ public final class DatagramChannelImpl extends DatagramChannel
|
||||
if (!isOpen())
|
||||
throw new ClosedChannelException();
|
||||
|
||||
socket.connect (remote);
|
||||
try
|
||||
{
|
||||
channel.connect((InetSocketAddress) remote, 0);
|
||||
}
|
||||
catch (ClassCastException cce)
|
||||
{
|
||||
throw new IOException("unsupported socked address type");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public DatagramChannel disconnect ()
|
||||
throws IOException
|
||||
{
|
||||
socket.disconnect ();
|
||||
channel.disconnect();
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isConnected ()
|
||||
public boolean isConnected()
|
||||
{
|
||||
return socket.isConnected ();
|
||||
try
|
||||
{
|
||||
return channel.getPeerAddress() != null;
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public int write (ByteBuffer src)
|
||||
@@ -138,7 +156,7 @@ public final class DatagramChannelImpl extends DatagramChannel
|
||||
if (!isConnected ())
|
||||
throw new NotYetConnectedException ();
|
||||
|
||||
return send (src, socket.getRemoteSocketAddress());
|
||||
return channel.write(src);
|
||||
}
|
||||
|
||||
public long write (ByteBuffer[] srcs, int offset, int length)
|
||||
@@ -152,13 +170,11 @@ public final class DatagramChannelImpl extends DatagramChannel
|
||||
|| (length < 0)
|
||||
|| (length > (srcs.length - offset)))
|
||||
throw new IndexOutOfBoundsException();
|
||||
|
||||
long result = 0;
|
||||
|
||||
for (int index = offset; index < offset + length; index++)
|
||||
result += write (srcs [index]);
|
||||
|
||||
return result;
|
||||
/* We are connected, meaning we will write these bytes to
|
||||
* the host we connected to, so we don't need to explicitly
|
||||
* give the host. */
|
||||
return channel.writeGathering(srcs, offset, length);
|
||||
}
|
||||
|
||||
public int read (ByteBuffer dst)
|
||||
@@ -167,9 +183,7 @@ public final class DatagramChannelImpl extends DatagramChannel
|
||||
if (!isConnected ())
|
||||
throw new NotYetConnectedException ();
|
||||
|
||||
int remaining = dst.remaining();
|
||||
receive (dst);
|
||||
return remaining - dst.remaining();
|
||||
return channel.read(dst);
|
||||
}
|
||||
|
||||
public long read (ByteBuffer[] dsts, int offset, int length)
|
||||
@@ -184,12 +198,8 @@ public final class DatagramChannelImpl extends DatagramChannel
|
||||
|| (length > (dsts.length - offset)))
|
||||
throw new IndexOutOfBoundsException();
|
||||
|
||||
long result = 0;
|
||||
|
||||
for (int index = offset; index < offset + length; index++)
|
||||
result += read (dsts [index]);
|
||||
|
||||
return result;
|
||||
/* Likewise, see the comment int write above. */
|
||||
return channel.readScattering(dsts, offset, length);
|
||||
}
|
||||
|
||||
public SocketAddress receive (ByteBuffer dst)
|
||||
@@ -200,49 +210,12 @@ public final class DatagramChannelImpl extends DatagramChannel
|
||||
|
||||
try
|
||||
{
|
||||
DatagramPacket packet;
|
||||
int len = dst.remaining();
|
||||
|
||||
if (dst.hasArray())
|
||||
{
|
||||
packet = new DatagramPacket (dst.array(),
|
||||
dst.arrayOffset() + dst.position(),
|
||||
len);
|
||||
}
|
||||
else
|
||||
{
|
||||
packet = new DatagramPacket (new byte [len], len);
|
||||
}
|
||||
|
||||
boolean completed = false;
|
||||
|
||||
try
|
||||
{
|
||||
begin();
|
||||
setInChannelOperation(true);
|
||||
socket.receive (packet);
|
||||
completed = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
end (completed);
|
||||
setInChannelOperation(false);
|
||||
}
|
||||
|
||||
if (!dst.hasArray())
|
||||
{
|
||||
dst.put (packet.getData(), packet.getOffset(), packet.getLength());
|
||||
}
|
||||
else
|
||||
{
|
||||
dst.position (dst.position() + packet.getLength());
|
||||
}
|
||||
|
||||
return packet.getSocketAddress();
|
||||
begin();
|
||||
return channel.receive(dst);
|
||||
}
|
||||
catch (SocketTimeoutException e)
|
||||
finally
|
||||
{
|
||||
return null;
|
||||
end(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,46 +225,18 @@ public final class DatagramChannelImpl extends DatagramChannel
|
||||
if (!isOpen())
|
||||
throw new ClosedChannelException();
|
||||
|
||||
if (target instanceof InetSocketAddress
|
||||
&& ((InetSocketAddress) target).isUnresolved())
|
||||
if (!(target instanceof InetSocketAddress))
|
||||
throw new IOException("can only send to inet socket addresses");
|
||||
|
||||
InetSocketAddress dst = (InetSocketAddress) target;
|
||||
if (dst.isUnresolved())
|
||||
throw new IOException("Target address not resolved");
|
||||
|
||||
byte[] buffer;
|
||||
int offset = 0;
|
||||
int len = src.remaining();
|
||||
|
||||
if (src.hasArray())
|
||||
{
|
||||
buffer = src.array();
|
||||
offset = src.arrayOffset() + src.position();
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = new byte [len];
|
||||
src.get (buffer);
|
||||
}
|
||||
|
||||
DatagramPacket packet = new DatagramPacket (buffer, offset, len, target);
|
||||
|
||||
boolean completed = false;
|
||||
try
|
||||
{
|
||||
begin();
|
||||
setInChannelOperation(true);
|
||||
socket.send(packet);
|
||||
completed = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
end (completed);
|
||||
setInChannelOperation(false);
|
||||
}
|
||||
|
||||
if (src.hasArray())
|
||||
{
|
||||
src.position (src.position() + len);
|
||||
}
|
||||
|
||||
return len;
|
||||
return channel.send(src, dst);
|
||||
}
|
||||
|
||||
public VMChannel getVMChannel()
|
||||
{
|
||||
return channel;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ exception statement from your version. */
|
||||
|
||||
package gnu.java.nio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.spi.AbstractSelectableChannel;
|
||||
|
||||
/**
|
||||
@@ -52,10 +53,16 @@ public final class DatagramChannelSelectionKey
|
||||
super (channel, selector);
|
||||
}
|
||||
|
||||
// FIXME don't use file descriptor integers
|
||||
public int getNativeFD()
|
||||
{
|
||||
NIODatagramSocket socket =
|
||||
(NIODatagramSocket) ((DatagramChannelImpl) ch).socket();
|
||||
return socket.getPlainDatagramSocketImpl().getNativeFD();
|
||||
try
|
||||
{
|
||||
return ((DatagramChannelImpl) ch).getVMChannel().getState().getNativeFD();
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
throw new IllegalStateException(ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
/* EpollSelectionKeyImpl.java -- selection key for the epoll selector.
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
GNU Classpath is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Classpath 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Classpath; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA.
|
||||
|
||||
Linking this library statically or dynamically with other modules is
|
||||
making a combined work based on this library. Thus, the terms and
|
||||
conditions of the GNU General Public License cover the whole
|
||||
combination.
|
||||
|
||||
As a special exception, the copyright holders of this library give you
|
||||
permission to link this library with independent modules to produce an
|
||||
executable, regardless of the license terms of these independent
|
||||
modules, and to copy and distribute the resulting executable under
|
||||
terms of your choice, provided that you also meet, for each linked
|
||||
independent module, the terms and conditions of the license of that
|
||||
module. An independent module is a module which is not derived from
|
||||
or based on this library. If you modify this library, you may extend
|
||||
this exception to your version of the library, but you are not
|
||||
obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. */
|
||||
|
||||
|
||||
package gnu.java.nio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.CancelledKeyException;
|
||||
import java.nio.channels.SelectableChannel;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.spi.AbstractSelectionKey;
|
||||
|
||||
/**
|
||||
* @author Casey Marshall (csm@gnu.org)
|
||||
*/
|
||||
public class EpollSelectionKeyImpl extends AbstractSelectionKey
|
||||
{
|
||||
final int fd;
|
||||
private final EpollSelectorImpl selector;
|
||||
private final SelectableChannel channel;
|
||||
int interestOps;
|
||||
int selectedOps;
|
||||
int key;
|
||||
boolean valid;
|
||||
boolean cancelled;
|
||||
|
||||
EpollSelectionKeyImpl(EpollSelectorImpl selector,
|
||||
SelectableChannel channel, int fd)
|
||||
{
|
||||
this.selector = selector;
|
||||
this.channel = channel;
|
||||
this.fd = fd;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.nio.channels.SelectionKey#channel()
|
||||
*/
|
||||
public SelectableChannel channel()
|
||||
{
|
||||
return channel;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.nio.channels.SelectionKey#interestOps()
|
||||
*/
|
||||
public int interestOps()
|
||||
{
|
||||
return interestOps;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.nio.channels.SelectionKey#interestOps(int)
|
||||
*/
|
||||
public SelectionKey interestOps(int ops)
|
||||
{
|
||||
if (cancelled)
|
||||
throw new CancelledKeyException();
|
||||
if ((ops & ~(channel.validOps())) != 0)
|
||||
throw new IllegalArgumentException("unsupported channel ops");
|
||||
try
|
||||
{
|
||||
selector.epoll_modify(this, ops);
|
||||
interestOps = ops;
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
throw new IllegalArgumentException(ioe);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.nio.channels.SelectionKey#readyOps()
|
||||
*/
|
||||
public int readyOps()
|
||||
{
|
||||
return selectedOps;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.nio.channels.SelectionKey#selector()
|
||||
*/
|
||||
public Selector selector()
|
||||
{
|
||||
return selector;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,399 @@
|
||||
/* EpollSelectorImpl.java -- selector implementation using epoll
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
GNU Classpath is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Classpath 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Classpath; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA.
|
||||
|
||||
Linking this library statically or dynamically with other modules is
|
||||
making a combined work based on this library. Thus, the terms and
|
||||
conditions of the GNU General Public License cover the whole
|
||||
combination.
|
||||
|
||||
As a special exception, the copyright holders of this library give you
|
||||
permission to link this library with independent modules to produce an
|
||||
executable, regardless of the license terms of these independent
|
||||
modules, and to copy and distribute the resulting executable under
|
||||
terms of your choice, provided that you also meet, for each linked
|
||||
independent module, the terms and conditions of the license of that
|
||||
module. An independent module is a module which is not derived from
|
||||
or based on this library. If you modify this library, you may extend
|
||||
this exception to your version of the library, but you are not
|
||||
obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. */
|
||||
|
||||
|
||||
package gnu.java.nio;
|
||||
|
||||
import gnu.classpath.Configuration;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SelectableChannel;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.spi.AbstractSelectableChannel;
|
||||
import java.nio.channels.spi.AbstractSelector;
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* An implementation of {@link Selector} that uses the epoll event
|
||||
* notification mechanism on GNU/Linux.
|
||||
*
|
||||
* @author Casey Marshall (csm@gnu.org)
|
||||
*/
|
||||
public class EpollSelectorImpl extends AbstractSelector
|
||||
{
|
||||
// XXX is this reasonable? Does it matter?
|
||||
private static final int DEFAULT_EPOLL_SIZE = 128;
|
||||
private static final int sizeof_struct_epoll_event;
|
||||
|
||||
private static final int OP_ACCEPT = SelectionKey.OP_ACCEPT;
|
||||
private static final int OP_CONNECT = SelectionKey.OP_CONNECT;
|
||||
private static final int OP_READ = SelectionKey.OP_READ;
|
||||
private static final int OP_WRITE = SelectionKey.OP_WRITE;
|
||||
|
||||
/** our epoll file descriptor. */
|
||||
private int epoll_fd;
|
||||
|
||||
private final HashMap keys;
|
||||
private Set selectedKeys;
|
||||
private Thread waitingThread;
|
||||
private ByteBuffer events;
|
||||
|
||||
private static final int INITIAL_CAPACITY;
|
||||
private static final int MAX_DOUBLING_CAPACITY;
|
||||
private static final int CAPACITY_INCREMENT;
|
||||
|
||||
static
|
||||
{
|
||||
if (Configuration.INIT_LOAD_LIBRARY)
|
||||
System.loadLibrary("javanio");
|
||||
|
||||
if (epoll_supported())
|
||||
sizeof_struct_epoll_event = sizeof_struct();
|
||||
else
|
||||
sizeof_struct_epoll_event = -1;
|
||||
|
||||
INITIAL_CAPACITY = 64 * sizeof_struct_epoll_event;
|
||||
MAX_DOUBLING_CAPACITY = 1024 * sizeof_struct_epoll_event;
|
||||
CAPACITY_INCREMENT = 128 * sizeof_struct_epoll_event;
|
||||
}
|
||||
|
||||
public EpollSelectorImpl(SelectorProvider provider)
|
||||
throws IOException
|
||||
{
|
||||
super(provider);
|
||||
epoll_fd = epoll_create(DEFAULT_EPOLL_SIZE);
|
||||
keys = new HashMap();
|
||||
selectedKeys = null;
|
||||
events = ByteBuffer.allocateDirect(INITIAL_CAPACITY);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.nio.channels.Selector#keys()
|
||||
*/
|
||||
public Set keys()
|
||||
{
|
||||
return new HashSet(keys.values());
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.nio.channels.Selector#select()
|
||||
*/
|
||||
public int select() throws IOException
|
||||
{
|
||||
return doSelect(-1);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.nio.channels.Selector#select(long)
|
||||
*/
|
||||
public int select(long timeout) throws IOException
|
||||
{
|
||||
if (timeout > Integer.MAX_VALUE)
|
||||
throw new IllegalArgumentException("timeout is too large");
|
||||
if (timeout < 0)
|
||||
throw new IllegalArgumentException("invalid timeout");
|
||||
return doSelect((int) timeout);
|
||||
}
|
||||
|
||||
private int doSelect(int timeout) throws IOException
|
||||
{
|
||||
synchronized (keys)
|
||||
{
|
||||
Set cancelledKeys = cancelledKeys();
|
||||
synchronized (cancelledKeys)
|
||||
{
|
||||
for (Iterator it = cancelledKeys.iterator(); it.hasNext(); )
|
||||
{
|
||||
EpollSelectionKeyImpl key = (EpollSelectionKeyImpl) it.next();
|
||||
epoll_delete(epoll_fd, key.fd);
|
||||
key.valid = false;
|
||||
keys.remove(Integer.valueOf(key.fd));
|
||||
it.remove();
|
||||
deregister(key);
|
||||
}
|
||||
|
||||
// Clear out closed channels. The fds are removed from the epoll
|
||||
// fd when closed, so there is no need to remove them manually.
|
||||
for (Iterator it = keys.values().iterator(); it.hasNext(); )
|
||||
{
|
||||
EpollSelectionKeyImpl key = (EpollSelectionKeyImpl) it.next();
|
||||
SelectableChannel ch = key.channel();
|
||||
if (ch instanceof VMChannelOwner)
|
||||
{
|
||||
if (!((VMChannelOwner) ch).getVMChannel().getState().isValid())
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// Don't bother if we have nothing to select.
|
||||
if (keys.isEmpty())
|
||||
return 0;
|
||||
|
||||
int ret;
|
||||
try
|
||||
{
|
||||
begin();
|
||||
waitingThread = Thread.currentThread();
|
||||
ret = epoll_wait(epoll_fd, events, keys.size(), timeout);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Thread.interrupted();
|
||||
waitingThread = null;
|
||||
end();
|
||||
}
|
||||
|
||||
HashSet s = new HashSet(ret);
|
||||
for (int i = 0; i < ret; i++)
|
||||
{
|
||||
events.position(i * sizeof_struct_epoll_event);
|
||||
ByteBuffer b = events.slice();
|
||||
int fd = selected_fd(b);
|
||||
EpollSelectionKeyImpl key
|
||||
= (EpollSelectionKeyImpl) keys.get(Integer.valueOf(fd));
|
||||
if (key == null)
|
||||
throw new IOException("fd was selected, but no key found");
|
||||
key.selectedOps = selected_ops(b) & key.interestOps;
|
||||
s.add(key);
|
||||
}
|
||||
|
||||
reallocateBuffer();
|
||||
|
||||
selectedKeys = s;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.nio.channels.Selector#selectedKeys()
|
||||
*/
|
||||
public Set selectedKeys()
|
||||
{
|
||||
if (selectedKeys == null)
|
||||
return Collections.EMPTY_SET;
|
||||
return selectedKeys;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.nio.channels.Selector#selectNow()
|
||||
*/
|
||||
public int selectNow() throws IOException
|
||||
{
|
||||
return doSelect(0);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.nio.channels.Selector#wakeup()
|
||||
*/
|
||||
public Selector wakeup()
|
||||
{
|
||||
try
|
||||
{
|
||||
waitingThread.interrupt();
|
||||
}
|
||||
catch (NullPointerException npe)
|
||||
{
|
||||
// Ignored, thrown if we are not in a blocking op.
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.nio.channels.spi.AbstractSelector#implCloseSelector()
|
||||
*/
|
||||
protected void implCloseSelector() throws IOException
|
||||
{
|
||||
VMChannel.close(epoll_fd);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.nio.channels.spi.AbstractSelector#register(java.nio.channels.spi.AbstractSelectableChannel, int, java.lang.Object)
|
||||
*/
|
||||
protected SelectionKey register(AbstractSelectableChannel ch, int ops, Object att)
|
||||
{
|
||||
if (!(ch instanceof VMChannelOwner))
|
||||
throw new IllegalArgumentException("unsupported channel type");
|
||||
|
||||
VMChannel channel = ((VMChannelOwner) ch).getVMChannel();
|
||||
try
|
||||
{
|
||||
int native_fd = channel.getState().getNativeFD();
|
||||
synchronized (keys)
|
||||
{
|
||||
if (keys.containsKey(Integer.valueOf(native_fd)))
|
||||
throw new IllegalArgumentException("channel already registered");
|
||||
EpollSelectionKeyImpl result =
|
||||
new EpollSelectionKeyImpl(this, ch, native_fd);
|
||||
if ((ops & ~(ch.validOps())) != 0)
|
||||
throw new IllegalArgumentException("invalid ops for channel");
|
||||
result.interestOps = ops;
|
||||
result.selectedOps = 0;
|
||||
result.valid = true;
|
||||
result.attach(att);
|
||||
result.key = System.identityHashCode(result);
|
||||
epoll_add(epoll_fd, result.fd, ops);
|
||||
keys.put(Integer.valueOf(native_fd), result);
|
||||
reallocateBuffer();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
throw new IllegalArgumentException(ioe);
|
||||
}
|
||||
}
|
||||
|
||||
private void reallocateBuffer()
|
||||
{
|
||||
// Ensure we have enough space for all potential events that may be
|
||||
// returned.
|
||||
if (events.capacity() < keys.size() * sizeof_struct_epoll_event)
|
||||
{
|
||||
int cap = events.capacity();
|
||||
if (cap < MAX_DOUBLING_CAPACITY)
|
||||
cap <<= 1;
|
||||
else
|
||||
cap += CAPACITY_INCREMENT;
|
||||
events = ByteBuffer.allocateDirect(cap);
|
||||
}
|
||||
// Ensure that the events buffer is not too large, given the number of
|
||||
// events registered.
|
||||
else if (events.capacity() > keys.size() * sizeof_struct_epoll_event * 2 + 1
|
||||
&& events.capacity() > INITIAL_CAPACITY)
|
||||
{
|
||||
int cap = events.capacity() >>> 1;
|
||||
events = ByteBuffer.allocateDirect(cap);
|
||||
}
|
||||
}
|
||||
|
||||
void epoll_modify(EpollSelectionKeyImpl key, int ops) throws IOException
|
||||
{
|
||||
epoll_modify(epoll_fd, key.fd, ops);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if epoll is supported by this system, and support was compiled in.
|
||||
*
|
||||
* @return True if this system supports event notification with epoll.
|
||||
*/
|
||||
public static native boolean epoll_supported();
|
||||
|
||||
|
||||
/**
|
||||
* Returns the size of `struct epoll_event'.
|
||||
*
|
||||
* @return The size of `struct epoll_event'.
|
||||
*/
|
||||
private static native int sizeof_struct();
|
||||
|
||||
|
||||
/**
|
||||
* Open a new epoll file descriptor.
|
||||
*
|
||||
* @param size The size hint for the new epoll descriptor.
|
||||
* @return The new file descriptor integer.
|
||||
* @throws IOException If allocating a new epoll descriptor fails.
|
||||
*/
|
||||
private static native int epoll_create(int size) throws IOException;
|
||||
|
||||
/**
|
||||
* Add a file descriptor to this selector.
|
||||
*
|
||||
* @param efd The epoll file descriptor.
|
||||
* @param fd The file descriptor to add (or modify).
|
||||
* @param ops The interest opts.
|
||||
*/
|
||||
private static native void epoll_add(int efd, int fd, int ops)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Modify the interest ops of the key selecting for the given FD.
|
||||
*
|
||||
* @param efd The epoll file descriptor.
|
||||
* @param fd The file descriptor to modify.
|
||||
* @param ops The ops.
|
||||
* @throws IOException
|
||||
*/
|
||||
private static native void epoll_modify(int efd, int fd, int ops)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Remove a file descriptor from this selector.
|
||||
*
|
||||
* @param efd The epoll file descriptor.
|
||||
* @param fd The file descriptor.
|
||||
* @throws IOException
|
||||
*/
|
||||
private static native void epoll_delete(int efd, int fd) throws IOException;
|
||||
|
||||
/**
|
||||
* Select events.
|
||||
*
|
||||
* @param efd The epoll file descriptor.
|
||||
* @param state The buffer to hold selected events.
|
||||
* @param n The number of events that may be put in `state'.
|
||||
* @param timeout The timeout.
|
||||
* @return The number of events selected.
|
||||
* @throws IOException
|
||||
*/
|
||||
private static native int epoll_wait(int efd, ByteBuffer state, int n, int timeout)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Fetch the fd value from a selected struct epoll_event.
|
||||
*
|
||||
* @param struct The direct buffer holding the struct.
|
||||
* @return The fd value.
|
||||
*/
|
||||
private static native int selected_fd(ByteBuffer struct);
|
||||
|
||||
/**
|
||||
* Fetch the enabled operations from a selected struct epoll_event.
|
||||
*
|
||||
* @param struct The direct buffer holding the struct.
|
||||
* @return The selected operations.
|
||||
*/
|
||||
private static native int selected_ops(ByteBuffer struct);
|
||||
}
|
||||
+96
-77
@@ -36,7 +36,7 @@ obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. */
|
||||
|
||||
|
||||
package gnu.java.nio.channels;
|
||||
package gnu.java.nio;
|
||||
|
||||
import gnu.classpath.Configuration;
|
||||
import gnu.java.nio.FileLockImpl;
|
||||
@@ -74,11 +74,11 @@ public final class FileChannelImpl extends FileChannel
|
||||
public static final int SYNC = 16;
|
||||
public static final int DSYNC = 32;
|
||||
|
||||
public static FileChannelImpl in;
|
||||
public static FileChannelImpl out;
|
||||
public static FileChannelImpl err;
|
||||
public static final FileChannelImpl in;
|
||||
public static final FileChannelImpl out;
|
||||
public static final FileChannelImpl err;
|
||||
|
||||
private static native void init();
|
||||
//private static native void init();
|
||||
|
||||
static
|
||||
{
|
||||
@@ -87,22 +87,45 @@ public final class FileChannelImpl extends FileChannel
|
||||
System.loadLibrary("javanio");
|
||||
}
|
||||
|
||||
init();
|
||||
//init();
|
||||
|
||||
in = new FileChannelImpl(0, READ);
|
||||
out = new FileChannelImpl(1, WRITE);
|
||||
err = new FileChannelImpl(2, WRITE);
|
||||
FileChannelImpl ch = null;
|
||||
try
|
||||
{
|
||||
ch = new FileChannelImpl(VMChannel.getStdin(), READ);
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
throw new Error(ioe);
|
||||
}
|
||||
in = ch;
|
||||
|
||||
ch = null;
|
||||
try
|
||||
{
|
||||
ch = new FileChannelImpl(VMChannel.getStdout(), WRITE);
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
throw new Error(ioe);
|
||||
}
|
||||
out = ch;
|
||||
|
||||
ch = null;
|
||||
try
|
||||
{
|
||||
ch = new FileChannelImpl(VMChannel.getStderr(), WRITE);
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
throw new Error(ioe);
|
||||
}
|
||||
err = ch;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the actual native file descriptor value
|
||||
*/
|
||||
// System's notion of file descriptor. It might seem redundant to
|
||||
// initialize this given that it is reassigned in the constructors.
|
||||
// However, this is necessary because if open() throws an exception
|
||||
// we want to make sure this has the value -1. This is the most
|
||||
// efficient way to accomplish that.
|
||||
private int fd = -1;
|
||||
private VMChannel ch;
|
||||
|
||||
private int mode;
|
||||
@@ -113,19 +136,19 @@ public final class FileChannelImpl extends FileChannel
|
||||
/* This is a static factory method, so that VM implementors can decide
|
||||
* substitute subclasses of FileChannelImpl. */
|
||||
public static FileChannelImpl create(File file, int mode)
|
||||
throws FileNotFoundException
|
||||
throws IOException
|
||||
{
|
||||
return new FileChannelImpl(file, mode);
|
||||
}
|
||||
|
||||
private FileChannelImpl(File file, int mode)
|
||||
throws FileNotFoundException
|
||||
throws IOException
|
||||
{
|
||||
String path = file.getPath();
|
||||
description = path;
|
||||
fd = open (path, mode);
|
||||
this.mode = mode;
|
||||
this.ch = VMChannel.getVMChannel(this);
|
||||
this.ch = new VMChannel();
|
||||
ch.openFile(path, mode);
|
||||
|
||||
// First open the file and then check if it is a a directory
|
||||
// to avoid race condition.
|
||||
@@ -133,11 +156,11 @@ public final class FileChannelImpl extends FileChannel
|
||||
{
|
||||
try
|
||||
{
|
||||
close();
|
||||
close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
/* ignore it */
|
||||
/* ignore it */
|
||||
}
|
||||
|
||||
throw new FileNotFoundException(description + " is a directory");
|
||||
@@ -153,49 +176,59 @@ public final class FileChannelImpl extends FileChannel
|
||||
*
|
||||
* @param mode READ or WRITE
|
||||
*/
|
||||
FileChannelImpl (int fd, int mode)
|
||||
FileChannelImpl (VMChannel ch, int mode)
|
||||
{
|
||||
this.fd = fd;
|
||||
this.mode = mode;
|
||||
this.description = "descriptor(" + fd + ")";
|
||||
this.ch = VMChannel.getVMChannel(this);
|
||||
this.description = "descriptor(" + ch.getState() + ")";
|
||||
this.ch = ch;
|
||||
}
|
||||
|
||||
private native int open (String path, int mode) throws FileNotFoundException;
|
||||
public int available() throws IOException
|
||||
{
|
||||
return ch.available();
|
||||
}
|
||||
|
||||
public native int available () throws IOException;
|
||||
private native long implPosition () throws IOException;
|
||||
private native void seek (long newPosition) throws IOException;
|
||||
private native void implTruncate (long size) throws IOException;
|
||||
private long implPosition() throws IOException
|
||||
{
|
||||
return ch.position();
|
||||
}
|
||||
|
||||
private void seek(long newPosition) throws IOException
|
||||
{
|
||||
ch.seek(newPosition);
|
||||
}
|
||||
|
||||
private void implTruncate(long size) throws IOException
|
||||
{
|
||||
ch.truncate(size);
|
||||
}
|
||||
|
||||
public native void unlock (long pos, long len) throws IOException;
|
||||
public void unlock(long pos, long len) throws IOException
|
||||
{
|
||||
ch.unlock(pos, len);
|
||||
}
|
||||
|
||||
public native long size () throws IOException;
|
||||
public long size () throws IOException
|
||||
{
|
||||
return ch.size();
|
||||
}
|
||||
|
||||
protected native void implCloseChannel() throws IOException;
|
||||
protected void implCloseChannel() throws IOException
|
||||
{
|
||||
ch.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure the Channel is properly closed.
|
||||
*/
|
||||
protected void finalize() throws IOException
|
||||
{
|
||||
if (fd != -1)
|
||||
if (ch.getState().isValid())
|
||||
close();
|
||||
}
|
||||
|
||||
public int read (ByteBuffer dst) throws IOException
|
||||
{
|
||||
/*
|
||||
int result;
|
||||
byte[] buffer = new byte [dst.remaining ()];
|
||||
|
||||
result = read (buffer, 0, buffer.length);
|
||||
|
||||
if (result > 0)
|
||||
dst.put (buffer, 0, result);
|
||||
|
||||
return result;
|
||||
*/
|
||||
return ch.read(dst);
|
||||
}
|
||||
|
||||
@@ -212,11 +245,10 @@ public final class FileChannelImpl extends FileChannel
|
||||
return result;
|
||||
}
|
||||
|
||||
public native int read ()
|
||||
throws IOException;
|
||||
|
||||
public native int read (byte[] buffer, int offset, int length)
|
||||
throws IOException;
|
||||
public int read() throws IOException
|
||||
{
|
||||
return ch.read();
|
||||
}
|
||||
|
||||
public long read (ByteBuffer[] dsts, int offset, int length)
|
||||
throws IOException
|
||||
@@ -252,19 +284,16 @@ public final class FileChannelImpl extends FileChannel
|
||||
return result;
|
||||
}
|
||||
|
||||
public native void write (byte[] buffer, int offset, int length)
|
||||
throws IOException;
|
||||
|
||||
public native void write (int b) throws IOException;
|
||||
public void write (int b) throws IOException
|
||||
{
|
||||
ch.write(b);
|
||||
}
|
||||
|
||||
public long write(ByteBuffer[] srcs, int offset, int length)
|
||||
throws IOException
|
||||
{
|
||||
return ch.writeGathering(srcs, offset, length);
|
||||
}
|
||||
|
||||
public native MappedByteBuffer mapImpl (char mode, long position, int size)
|
||||
throws IOException;
|
||||
|
||||
public MappedByteBuffer map (FileChannel.MapMode mode,
|
||||
long position, long size)
|
||||
@@ -291,7 +320,7 @@ public final class FileChannelImpl extends FileChannel
|
||||
if (position < 0 || size < 0 || size > Integer.MAX_VALUE)
|
||||
throw new IllegalArgumentException ("position: " + position
|
||||
+ ", size: " + size);
|
||||
return mapImpl(nmode, position, (int) size);
|
||||
return ch.map(nmode, position, (int) size);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -302,11 +331,9 @@ public final class FileChannelImpl extends FileChannel
|
||||
if (!isOpen ())
|
||||
throw new ClosedChannelException ();
|
||||
|
||||
force ();
|
||||
ch.flush(metaData);
|
||||
}
|
||||
|
||||
private native void force ();
|
||||
|
||||
// like transferTo, but with a count of less than 2Gbytes
|
||||
private int smallTransferTo (long position, int count,
|
||||
WritableByteChannel target)
|
||||
@@ -453,7 +480,7 @@ public final class FileChannelImpl extends FileChannel
|
||||
try
|
||||
{
|
||||
begin();
|
||||
boolean lockable = lock(position, size, shared, false);
|
||||
boolean lockable = ch.lock(position, size, shared, false);
|
||||
completed = true;
|
||||
return (lockable
|
||||
? new FileLockImpl(this, position, size, shared)
|
||||
@@ -464,14 +491,6 @@ public final class FileChannelImpl extends FileChannel
|
||||
end(completed);
|
||||
}
|
||||
}
|
||||
|
||||
/** Try to acquire a lock at the given position and size.
|
||||
* On success return true.
|
||||
* If wait as specified, block until we can get it.
|
||||
* Otherwise return false.
|
||||
*/
|
||||
private native boolean lock(long position, long size,
|
||||
boolean shared, boolean wait) throws IOException;
|
||||
|
||||
public FileLock lock (long position, long size, boolean shared)
|
||||
throws IOException
|
||||
@@ -481,7 +500,7 @@ public final class FileChannelImpl extends FileChannel
|
||||
boolean completed = false;
|
||||
try
|
||||
{
|
||||
boolean lockable = lock(position, size, shared, true);
|
||||
boolean lockable = ch.lock(position, size, shared, true);
|
||||
completed = true;
|
||||
return (lockable
|
||||
? new FileLockImpl(this, position, size, shared)
|
||||
@@ -537,17 +556,17 @@ public final class FileChannelImpl extends FileChannel
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return (this.getClass()
|
||||
+ "[fd=" + fd
|
||||
+ ",mode=" + mode + ","
|
||||
+ description + "]");
|
||||
return (super.toString()
|
||||
+ "[ fd: " + ch.getState()
|
||||
+ "; mode: " + Integer.toOctalString(mode)
|
||||
+ "; " + description + " ]");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The native file descriptor.
|
||||
*/
|
||||
* /
|
||||
public int getNativeFD()
|
||||
{
|
||||
return fd;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
@@ -38,8 +38,6 @@ exception statement from your version. */
|
||||
|
||||
package gnu.java.nio;
|
||||
|
||||
import gnu.java.nio.channels.FileChannelImpl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.FileLock;
|
||||
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
/* KqueueSelectionKeyImpl.java -- selection key for kqueue/kevent.
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
GNU Classpath is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Classpath 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Classpath; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA.
|
||||
|
||||
Linking this library statically or dynamically with other modules is
|
||||
making a combined work based on this library. Thus, the terms and
|
||||
conditions of the GNU General Public License cover the whole
|
||||
combination.
|
||||
|
||||
As a special exception, the copyright holders of this library give you
|
||||
permission to link this library with independent modules to produce an
|
||||
executable, regardless of the license terms of these independent
|
||||
modules, and to copy and distribute the resulting executable under
|
||||
terms of your choice, provided that you also meet, for each linked
|
||||
independent module, the terms and conditions of the license of that
|
||||
module. An independent module is a module which is not derived from
|
||||
or based on this library. If you modify this library, you may extend
|
||||
this exception to your version of the library, but you are not
|
||||
obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. */
|
||||
|
||||
|
||||
package gnu.java.nio;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SelectableChannel;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.spi.AbstractSelectionKey;
|
||||
|
||||
/**
|
||||
* @author Casey Marshall (csm@gnu.org)
|
||||
*/
|
||||
public class KqueueSelectionKeyImpl extends AbstractSelectionKey
|
||||
{
|
||||
int interestOps;
|
||||
int readyOps;
|
||||
int activeOps = 0;
|
||||
int key;
|
||||
int fd;
|
||||
|
||||
/** The selector we were created for. */
|
||||
private final KqueueSelectorImpl selector;
|
||||
|
||||
/** The channel we are attached to. */
|
||||
private final SelectableChannel channel;
|
||||
|
||||
private final VMChannelOwner natChannel;
|
||||
|
||||
public KqueueSelectionKeyImpl(KqueueSelectorImpl selector,
|
||||
SelectableChannel channel)
|
||||
{
|
||||
this.selector = selector;
|
||||
this.channel = channel;
|
||||
natChannel = (VMChannelOwner) channel;
|
||||
interestOps = 0;
|
||||
readyOps = 0;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.nio.channels.SelectionKey#channel()
|
||||
*/
|
||||
//@Override
|
||||
public SelectableChannel channel()
|
||||
{
|
||||
return channel;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.nio.channels.SelectionKey#interestOps()
|
||||
*/
|
||||
//@Override
|
||||
public int interestOps()
|
||||
{
|
||||
return interestOps;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.nio.channels.SelectionKey#interestOps(int)
|
||||
*/
|
||||
//@Override
|
||||
public SelectionKey interestOps(int ops)
|
||||
{
|
||||
if (!isValid())
|
||||
throw new IllegalStateException("key is invalid");
|
||||
if ((ops & ~channel.validOps()) != 0)
|
||||
throw new IllegalArgumentException("channel does not support all operations");
|
||||
|
||||
selector.setInterestOps(this, ops);
|
||||
return this;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.nio.channels.SelectionKey#readyOps()
|
||||
*/
|
||||
//@Override
|
||||
public int readyOps()
|
||||
{
|
||||
return readyOps;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.nio.channels.SelectionKey#selector()
|
||||
*/
|
||||
//@Override
|
||||
public Selector selector()
|
||||
{
|
||||
return selector;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
if (!isValid())
|
||||
return super.toString() + " [ fd: " + fd + " <<invalid>> ]";
|
||||
return super.toString() + " [ fd: " + fd + " interest ops: {"
|
||||
+ ((interestOps & OP_ACCEPT) != 0 ? " OP_ACCEPT" : "")
|
||||
+ ((interestOps & OP_CONNECT) != 0 ? " OP_CONNECT" : "")
|
||||
+ ((interestOps & OP_READ) != 0 ? " OP_READ" : "")
|
||||
+ ((interestOps & OP_WRITE) != 0 ? " OP_WRITE" : "")
|
||||
+ " }; ready ops: {"
|
||||
+ ((readyOps & OP_ACCEPT) != 0 ? " OP_ACCEPT" : "")
|
||||
+ ((readyOps & OP_CONNECT) != 0 ? " OP_CONNECT" : "")
|
||||
+ ((readyOps & OP_READ) != 0 ? " OP_READ" : "")
|
||||
+ ((readyOps & OP_WRITE) != 0 ? " OP_WRITE" : "")
|
||||
+ " } ]";
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return fd;
|
||||
}
|
||||
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (!(o instanceof KqueueSelectionKeyImpl))
|
||||
return false;
|
||||
KqueueSelectionKeyImpl that = (KqueueSelectionKeyImpl) o;
|
||||
return that.fd == this.fd && that.channel.equals(this.channel);
|
||||
}
|
||||
|
||||
|
||||
boolean isReadActive()
|
||||
{
|
||||
return (activeOps & (OP_READ | OP_ACCEPT)) != 0;
|
||||
}
|
||||
|
||||
boolean isReadInterested()
|
||||
{
|
||||
return (interestOps & (OP_READ | OP_ACCEPT)) != 0;
|
||||
}
|
||||
|
||||
boolean isWriteActive()
|
||||
{
|
||||
return (activeOps & (OP_WRITE | OP_CONNECT)) != 0;
|
||||
}
|
||||
|
||||
boolean isWriteInterested()
|
||||
{
|
||||
return (interestOps & (OP_WRITE | OP_CONNECT)) != 0;
|
||||
}
|
||||
|
||||
boolean needCommitRead()
|
||||
{
|
||||
return isReadActive() == (!isReadInterested());
|
||||
}
|
||||
|
||||
boolean needCommitWrite()
|
||||
{
|
||||
return isWriteActive() == (!isWriteInterested());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,527 @@
|
||||
/* KqueueSelectorImpl.java -- Selector for systems with kqueue event notification.
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
GNU Classpath is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Classpath 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Classpath; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA.
|
||||
|
||||
Linking this library statically or dynamically with other modules is
|
||||
making a combined work based on this library. Thus, the terms and
|
||||
conditions of the GNU General Public License cover the whole
|
||||
combination.
|
||||
|
||||
As a special exception, the copyright holders of this library give you
|
||||
permission to link this library with independent modules to produce an
|
||||
executable, regardless of the license terms of these independent
|
||||
modules, and to copy and distribute the resulting executable under
|
||||
terms of your choice, provided that you also meet, for each linked
|
||||
independent module, the terms and conditions of the license of that
|
||||
module. An independent module is a module which is not derived from
|
||||
or based on this library. If you modify this library, you may extend
|
||||
this exception to your version of the library, but you are not
|
||||
obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. */
|
||||
|
||||
|
||||
package gnu.java.nio;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.channels.ClosedSelectorException;
|
||||
import java.nio.channels.SelectableChannel;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.spi.AbstractSelectableChannel;
|
||||
import java.nio.channels.spi.AbstractSelector;
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A {@link Selector} implementation that uses the <code>kqueue</code>
|
||||
* event notification facility.
|
||||
*
|
||||
* @author Casey Marshall (csm@gnu.org)
|
||||
*/
|
||||
public class KqueueSelectorImpl extends AbstractSelector
|
||||
{
|
||||
// Prepended underscore to field name to make it distinct
|
||||
// from the method with the similar name.
|
||||
private static final int _sizeof_struct_kevent;
|
||||
|
||||
private static final int MAX_DOUBLING_CAPACITY = 16384;
|
||||
private static final int CAP_INCREMENT = 1024;
|
||||
private static final int INITIAL_CAPACITY;
|
||||
|
||||
static
|
||||
{
|
||||
try
|
||||
{
|
||||
System.loadLibrary("javanio");
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
x.printStackTrace();
|
||||
}
|
||||
|
||||
if (kqueue_supported ())
|
||||
_sizeof_struct_kevent = sizeof_struct_kevent();
|
||||
else
|
||||
_sizeof_struct_kevent = -1;
|
||||
INITIAL_CAPACITY = 16 * _sizeof_struct_kevent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if kqueue-based selectors are supported on this system.
|
||||
*
|
||||
* @return True if this system has kqueue support, and support for it was
|
||||
* compiled in to Classpath.
|
||||
*/
|
||||
public static native boolean kqueue_supported();
|
||||
|
||||
/* Our native file descriptor. */
|
||||
private int kq;
|
||||
|
||||
private HashMap/*<Integer,KqueueSelectionKeyImpl>*/ keys;
|
||||
private HashSet/*<KqueueSelectionKeyImpl>*/ selected;
|
||||
private Thread blockedThread;
|
||||
private ByteBuffer events;
|
||||
|
||||
private static final int OP_ACCEPT = SelectionKey.OP_ACCEPT;
|
||||
private static final int OP_CONNECT = SelectionKey.OP_CONNECT;
|
||||
private static final int OP_READ = SelectionKey.OP_READ;
|
||||
private static final int OP_WRITE = SelectionKey.OP_WRITE;
|
||||
|
||||
public KqueueSelectorImpl(SelectorProvider provider) throws IOException
|
||||
{
|
||||
super(provider);
|
||||
kq = implOpen();
|
||||
keys = new HashMap/*<KqueueSelectionKeyImpl>*/();
|
||||
events = ByteBuffer.allocateDirect(INITIAL_CAPACITY);
|
||||
}
|
||||
|
||||
protected void implCloseSelector() throws IOException
|
||||
{
|
||||
implClose(kq);
|
||||
kq = -1;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.nio.channels.Selector#keys()
|
||||
*/
|
||||
public Set keys()
|
||||
{
|
||||
if (!isOpen())
|
||||
throw new ClosedSelectorException();
|
||||
|
||||
return new HashSet(keys.values());
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.nio.channels.Selector#select()
|
||||
*/
|
||||
public int select() throws IOException
|
||||
{
|
||||
return doSelect(-1);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.nio.channels.Selector#select(long)
|
||||
*/
|
||||
public int select(long timeout) throws IOException
|
||||
{
|
||||
if (timeout == 0)
|
||||
timeout = -1;
|
||||
return doSelect(timeout);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.nio.channels.Selector#selectedKeys()
|
||||
*/
|
||||
public Set selectedKeys()
|
||||
{
|
||||
if (!isOpen())
|
||||
throw new ClosedSelectorException();
|
||||
|
||||
return selected;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.nio.channels.Selector#selectNow()
|
||||
*/
|
||||
public int selectNow() throws IOException
|
||||
{
|
||||
return doSelect(0);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.nio.channels.Selector#wakeup()
|
||||
*/
|
||||
public Selector wakeup()
|
||||
{
|
||||
if (blockedThread != null)
|
||||
blockedThread.interrupt();
|
||||
return this;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return super.toString() + " [ fd: " + kq + " ]";
|
||||
}
|
||||
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (!(o instanceof KqueueSelectorImpl))
|
||||
return false;
|
||||
|
||||
return ((KqueueSelectorImpl) o).kq == kq;
|
||||
}
|
||||
|
||||
int doSelect(long timeout) throws IOException
|
||||
{
|
||||
Set cancelled = cancelledKeys();
|
||||
synchronized (cancelled)
|
||||
{
|
||||
synchronized (keys)
|
||||
{
|
||||
for (Iterator it = cancelled.iterator(); it.hasNext(); )
|
||||
{
|
||||
KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) it.next();
|
||||
key.interestOps = 0;
|
||||
}
|
||||
|
||||
int events_size = (2 * _sizeof_struct_kevent) * keys.size();
|
||||
int num_events = 0;
|
||||
|
||||
for (Iterator it = keys.entrySet().iterator(); it.hasNext(); )
|
||||
{
|
||||
Map.Entry e = (Map.Entry) it.next();
|
||||
KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) e.getValue();
|
||||
|
||||
SelectableChannel ch = key.channel();
|
||||
if (ch instanceof VMChannelOwner)
|
||||
{
|
||||
if (!((VMChannelOwner) ch).getVMChannel().getState().isValid())
|
||||
{
|
||||
// closed channel; removed from kqueue automatically.
|
||||
it.remove();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// If this key is registering a read filter, add it to the buffer.
|
||||
if (key.needCommitRead())
|
||||
{
|
||||
kevent_set(events, num_events, key.fd,
|
||||
key.interestOps & (OP_READ | OP_ACCEPT),
|
||||
key.activeOps & (OP_READ | OP_ACCEPT), key.key);
|
||||
num_events++;
|
||||
}
|
||||
|
||||
// If this key is registering a write filter, add it to the buffer.
|
||||
if (key.needCommitWrite())
|
||||
{
|
||||
kevent_set(events, num_events, key.fd,
|
||||
key.interestOps & (OP_WRITE | OP_CONNECT),
|
||||
key.activeOps & (OP_WRITE | OP_CONNECT), key.key);
|
||||
num_events++;
|
||||
}
|
||||
}
|
||||
events.rewind().limit(events.capacity());
|
||||
|
||||
//System.out.println("dump of keys to select:");
|
||||
//dump_selection_keys(events.duplicate());
|
||||
|
||||
int n = 0;
|
||||
try
|
||||
{
|
||||
//System.out.println("[" + kq + "] kevent enter selecting from " + keys.size());
|
||||
begin();
|
||||
blockedThread = Thread.currentThread();
|
||||
if (blockedThread.isInterrupted())
|
||||
timeout = 0;
|
||||
n = kevent(kq, events, num_events,
|
||||
events.capacity() / _sizeof_struct_kevent, timeout);
|
||||
}
|
||||
finally
|
||||
{
|
||||
end();
|
||||
blockedThread = null;
|
||||
Thread.interrupted();
|
||||
//System.out.println("[" + kq + "kevent exit selected " + n);
|
||||
}
|
||||
|
||||
//System.out.println("dump of keys selected:");
|
||||
//dump_selection_keys((ByteBuffer) events.duplicate().limit(n * _sizeof_struct_kevent));
|
||||
|
||||
// Commit the operations we've just added in the call to kevent.
|
||||
for (Iterator it = keys.values().iterator(); it.hasNext(); )
|
||||
{
|
||||
KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) it.next();
|
||||
key.activeOps = key.interestOps;
|
||||
}
|
||||
|
||||
selected = new HashSet/*<KqueueSelectionKeyImpl>*/(n);
|
||||
int x = 0;
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
events.position(x).limit(x + _sizeof_struct_kevent);
|
||||
x += _sizeof_struct_kevent;
|
||||
int y = fetch_key(events.slice());
|
||||
KqueueSelectionKeyImpl key =
|
||||
(KqueueSelectionKeyImpl) keys.get(new Integer(y));
|
||||
|
||||
if (key == null)
|
||||
{
|
||||
System.out.println("WARNING! no key found for selected key " + y);
|
||||
continue;
|
||||
}
|
||||
// Keys that have been cancelled may be returned here; don't
|
||||
// add them to the selected set.
|
||||
if (!key.isValid())
|
||||
continue;
|
||||
key.readyOps = ready_ops(events.slice(), key.interestOps);
|
||||
selected.add(key);
|
||||
}
|
||||
|
||||
// Finally, remove the cancelled keys.
|
||||
for (Iterator it = cancelled.iterator(); it.hasNext(); )
|
||||
{
|
||||
KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) it.next();
|
||||
keys.remove(new Integer(key.key));
|
||||
deregister(key);
|
||||
it.remove();
|
||||
}
|
||||
|
||||
reallocateBuffer();
|
||||
|
||||
return selected.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected SelectionKey register(AbstractSelectableChannel channel,
|
||||
int interestOps,
|
||||
Object attachment)
|
||||
{
|
||||
int native_fd = -1;
|
||||
try
|
||||
{
|
||||
if (channel instanceof VMChannelOwner)
|
||||
native_fd = ((VMChannelOwner) channel).getVMChannel()
|
||||
.getState().getNativeFD();
|
||||
else
|
||||
throw new IllegalArgumentException("cannot handle channel type " +
|
||||
channel.getClass().getName());
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
throw new IllegalArgumentException("channel is closed or invalid");
|
||||
}
|
||||
|
||||
KqueueSelectionKeyImpl result = new KqueueSelectionKeyImpl(this, channel);
|
||||
result.interestOps = interestOps;
|
||||
result.attach(attachment);
|
||||
result.fd = native_fd;
|
||||
result.key = System.identityHashCode(result);
|
||||
synchronized (keys)
|
||||
{
|
||||
while (keys.containsKey(new Integer(result.key)))
|
||||
result.key++;
|
||||
keys.put(new Integer(result.key), result);
|
||||
reallocateBuffer();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void setInterestOps(KqueueSelectionKeyImpl key, int ops)
|
||||
{
|
||||
synchronized (keys)
|
||||
{
|
||||
key.interestOps = ops;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reallocate the events buffer. This is the destination buffer for
|
||||
* events returned by kevent. This method will:
|
||||
*
|
||||
* * Grow the buffer if there is insufficent space for all registered
|
||||
* events.
|
||||
* * Shrink the buffer if it is more than twice the size needed.
|
||||
*
|
||||
*/
|
||||
private void reallocateBuffer()
|
||||
{
|
||||
synchronized (keys)
|
||||
{
|
||||
if (events.capacity() < (2 * _sizeof_struct_kevent) * keys.size())
|
||||
{
|
||||
int cap = events.capacity();
|
||||
if (cap >= MAX_DOUBLING_CAPACITY)
|
||||
cap += CAP_INCREMENT;
|
||||
else
|
||||
cap = cap << 1;
|
||||
|
||||
events = ByteBuffer.allocateDirect(cap);
|
||||
}
|
||||
else if (events.capacity() > 4 * (_sizeof_struct_kevent) * keys.size() + 1
|
||||
&& events.capacity() > INITIAL_CAPACITY)
|
||||
{
|
||||
int cap = events.capacity();
|
||||
cap = cap >>> 1;
|
||||
events = ByteBuffer.allocateDirect(cap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//synchronized void updateOps(KqueueSelectionKeyImpl key, int interestOps)
|
||||
//{
|
||||
// updateOps(key, interestOps, 0, false);
|
||||
//}
|
||||
|
||||
/*void updateOps(KqueueSelectionKeyImpl key, int interestOps,
|
||||
int activeOps, int fd)
|
||||
{
|
||||
//System.out.println(">> updating kqueue selection key:");
|
||||
//dump_selection_keys(key.nstate.duplicate());
|
||||
//System.out.println("<<");
|
||||
synchronized (keys)
|
||||
{
|
||||
kevent_set(key.nstate, fd, interestOps, activeOps, key.key);
|
||||
}
|
||||
//System.out.println(">> updated kqueue selection key:");
|
||||
//dump_selection_keys(key.nstate.duplicate());
|
||||
//System.out.println("<<");
|
||||
}*/
|
||||
|
||||
private void dump_selection_keys(ByteBuffer keys)
|
||||
{
|
||||
// WARNING! This method is not guaranteed to be portable! This works
|
||||
// on darwin/x86, but the sizeof and offsetof these fields may be
|
||||
// different on other platforms!
|
||||
int i = 0;
|
||||
keys.order(ByteOrder.nativeOrder());
|
||||
while (keys.hasRemaining())
|
||||
{
|
||||
System.out.println("struct kevent { ident: "
|
||||
+ Integer.toString(keys.getInt())
|
||||
+ " filter: "
|
||||
+ Integer.toHexString(keys.getShort() & 0xFFFF)
|
||||
+ " flags: "
|
||||
+ Integer.toHexString(keys.getShort() & 0xFFFF)
|
||||
+ " fflags: "
|
||||
+ Integer.toHexString(keys.getInt())
|
||||
+ " data: "
|
||||
+ Integer.toHexString(keys.getInt())
|
||||
+ " udata: "
|
||||
+ Integer.toHexString(keys.getInt())
|
||||
+ " }");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size of a <code>struct kevent</code> on this system.
|
||||
*
|
||||
* @return The size of <code>struct kevent</code>.
|
||||
*/
|
||||
private static native int sizeof_struct_kevent();
|
||||
|
||||
/**
|
||||
* Opens a kqueue descriptor.
|
||||
*
|
||||
* @return The new kqueue descriptor.
|
||||
* @throws IOException If opening fails.
|
||||
*/
|
||||
private static native int implOpen() throws IOException;
|
||||
|
||||
/**
|
||||
* Closes the kqueue file descriptor.
|
||||
*
|
||||
* @param kq The kqueue file descriptor.
|
||||
* @throws IOException
|
||||
*/
|
||||
private static native void implClose(int kq) throws IOException;
|
||||
|
||||
/**
|
||||
* Initialize the specified native state for the given interest ops.
|
||||
*
|
||||
* @param nstate The native state structures; in this buffer should be
|
||||
* the <code>struct kevent</code>s created for a key.
|
||||
* @param fd The file descriptor. If 0, the native FD is unmodified.
|
||||
* @param interestOps The operations to enable.
|
||||
* @param key A unique key that will reference the associated key later.
|
||||
* @param delete Set to true if this event should be deleted from the
|
||||
* kqueue (if false, this event is added/updated).
|
||||
*/
|
||||
private static native void kevent_set(ByteBuffer nstate, int i, int fd,
|
||||
int interestOps, int activeOps, int key);
|
||||
|
||||
/**
|
||||
* Poll for events. The source events are stored in <code>events</code>,
|
||||
* which is also where polled events will be placed.
|
||||
*
|
||||
* @param events The events to poll. This buffer is also the destination
|
||||
* for events read from the queue.
|
||||
* @param nevents The number of events to poll (that is, the number of
|
||||
* events in the <code>events</code> buffer).
|
||||
* @param nout The maximum number of events that may be returned.
|
||||
* @param timeout The timeout. A timeout of -1 returns immediately; a timeout
|
||||
* of 0 waits indefinitely.
|
||||
* @return The number of events read.
|
||||
*/
|
||||
private static native int kevent(int kq, ByteBuffer events, int nevents,
|
||||
int nout, long timeout);
|
||||
|
||||
/**
|
||||
* Fetch a polled key from a native state buffer. For each kevent key we
|
||||
* create, we put the native state info (one or more <code>struct
|
||||
* kevent</code>s) in that key's {@link KqueueSelectionKeyImpl#nstate}
|
||||
* buffer, and place the pointer of the key in the <code>udata</code> field
|
||||
* of that structure. This method fetches that pointer from the given
|
||||
* buffer (assumed to be a <code>struct kqueue</code>) and returns it.
|
||||
*
|
||||
* @param nstate The buffer containing the <code>struct kqueue</code> to read.
|
||||
* @return The key object.
|
||||
*/
|
||||
private static native int fetch_key(ByteBuffer nstate);
|
||||
|
||||
/**
|
||||
* Fetch the ready ops of the associated native state. That is, this
|
||||
* inspects the first argument as a <code>struct kevent</code>, looking
|
||||
* at its operation (the input is assumed to have been returned via a
|
||||
* previous call to <code>kevent</code>), and translating that to the
|
||||
* appropriate Java bit set, based on the second argument.
|
||||
*
|
||||
* @param nstate The native state.
|
||||
* @param interestOps The enabled operations for the key.
|
||||
* @return The bit set representing the ready operations.
|
||||
*/
|
||||
private static native int ready_ops(ByteBuffer nstate, int interestOps);
|
||||
|
||||
/**
|
||||
* Check if kevent returned EV_EOF for a selection key.
|
||||
*
|
||||
* @param nstate The native state.
|
||||
* @return True if the kevent call returned EOF.
|
||||
*/
|
||||
private static native boolean check_eof(ByteBuffer nstate);
|
||||
}
|
||||
@@ -48,30 +48,33 @@ import java.nio.channels.SocketChannel;
|
||||
*/
|
||||
public final class NIOSocket extends Socket
|
||||
{
|
||||
private PlainSocketImpl impl;
|
||||
private SocketChannelImpl channel;
|
||||
|
||||
protected NIOSocket (PlainSocketImpl impl, SocketChannelImpl channel)
|
||||
protected NIOSocket (SocketChannelImpl channel)
|
||||
throws IOException
|
||||
{
|
||||
super (impl);
|
||||
this.impl = impl;
|
||||
super (new NIOSocketImpl(channel));
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
public final PlainSocketImpl getPlainSocketImpl()
|
||||
{
|
||||
return impl;
|
||||
}
|
||||
//public final PlainSocketImpl getPlainSocketImpl()
|
||||
//{
|
||||
// return impl;
|
||||
//}
|
||||
|
||||
final void setChannel (SocketChannelImpl channel)
|
||||
{
|
||||
this.impl = channel.getPlainSocketImpl();
|
||||
this.channel = channel;
|
||||
}
|
||||
//final void setChannel (SocketChannelImpl channel)
|
||||
//{
|
||||
// this.impl = channel.getPlainSocketImpl();
|
||||
// this.channel = channel;
|
||||
//}
|
||||
|
||||
public final SocketChannel getChannel()
|
||||
{
|
||||
return channel;
|
||||
}
|
||||
|
||||
public boolean isConnected()
|
||||
{
|
||||
return channel.isConnected();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
/* NIOSocketImpl.java -- subclass of PlainSocketImpl for NIO.
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
GNU Classpath is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Classpath 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Classpath; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA.
|
||||
|
||||
Linking this library statically or dynamically with other modules is
|
||||
making a combined work based on this library. Thus, the terms and
|
||||
conditions of the GNU General Public License cover the whole
|
||||
combination.
|
||||
|
||||
As a special exception, the copyright holders of this library give you
|
||||
permission to link this library with independent modules to produce an
|
||||
executable, regardless of the license terms of these independent
|
||||
modules, and to copy and distribute the resulting executable under
|
||||
terms of your choice, provided that you also meet, for each linked
|
||||
independent module, the terms and conditions of the license of that
|
||||
module. An independent module is a module which is not derived from
|
||||
or based on this library. If you modify this library, you may extend
|
||||
this exception to your version of the library, but you are not
|
||||
obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. */
|
||||
|
||||
|
||||
package gnu.java.nio;
|
||||
|
||||
import gnu.java.net.PlainSocketImpl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
|
||||
/**
|
||||
* @author Casey Marshall (csm@gnu.org)
|
||||
*/
|
||||
public class NIOSocketImpl extends PlainSocketImpl
|
||||
{
|
||||
|
||||
private final SocketChannelImpl channel;
|
||||
|
||||
NIOSocketImpl(SocketChannelImpl channel) throws IOException
|
||||
{
|
||||
this.channel = channel;
|
||||
impl.getState().setChannelFD(channel.getVMChannel().getState());
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.net.SocketImpl#getInetAddress()
|
||||
*/
|
||||
//@Override
|
||||
protected InetAddress getInetAddress()
|
||||
{
|
||||
try
|
||||
{
|
||||
return channel.getVMChannel().getPeerAddress().getAddress();
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
catch (NullPointerException npe)
|
||||
{
|
||||
// Socket is not connected yet.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.net.SocketImpl#getPort()
|
||||
*/
|
||||
//@Override
|
||||
protected int getPort()
|
||||
{
|
||||
try
|
||||
{
|
||||
return channel.getVMChannel().getPeerAddress().getPort();
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
catch (NullPointerException npe)
|
||||
{
|
||||
// Socket is not connected yet.
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see gnu.java.net.PlainSocketImpl#create(boolean)
|
||||
*/
|
||||
//@Override
|
||||
protected synchronized void create(boolean stream)
|
||||
{
|
||||
// Ignored; the socket has already been created.
|
||||
}
|
||||
}
|
||||
@@ -46,22 +46,21 @@ import java.nio.channels.spi.SelectorProvider;
|
||||
class PipeImpl extends Pipe
|
||||
{
|
||||
public static final class SourceChannelImpl extends Pipe.SourceChannel
|
||||
implements VMChannelOwner
|
||||
{
|
||||
private int native_fd;
|
||||
private VMChannel vmch;
|
||||
|
||||
public SourceChannelImpl (SelectorProvider selectorProvider,
|
||||
int native_fd)
|
||||
VMChannel channel)
|
||||
{
|
||||
super (selectorProvider);
|
||||
this.native_fd = native_fd;
|
||||
vmch = VMChannel.getVMChannel(this);
|
||||
vmch = channel;
|
||||
}
|
||||
|
||||
protected final void implCloseSelectableChannel()
|
||||
throws IOException
|
||||
{
|
||||
throw new Error ("Not implemented");
|
||||
vmch.close();
|
||||
}
|
||||
|
||||
protected void implConfigureBlocking (boolean blocking)
|
||||
@@ -94,30 +93,29 @@ class PipeImpl extends Pipe
|
||||
|
||||
return vmch.readScattering(srcs, offset, len);
|
||||
}
|
||||
|
||||
public final int getNativeFD()
|
||||
|
||||
public VMChannel getVMChannel()
|
||||
{
|
||||
return native_fd;
|
||||
return vmch;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class SinkChannelImpl extends Pipe.SinkChannel
|
||||
implements VMChannelOwner
|
||||
{
|
||||
private int native_fd;
|
||||
private VMChannel vmch;
|
||||
|
||||
public SinkChannelImpl (SelectorProvider selectorProvider,
|
||||
int native_fd)
|
||||
VMChannel channel)
|
||||
{
|
||||
super (selectorProvider);
|
||||
this.native_fd = native_fd;
|
||||
vmch = VMChannel.getVMChannel(this);
|
||||
vmch = channel;
|
||||
}
|
||||
|
||||
protected final void implCloseSelectableChannel()
|
||||
throws IOException
|
||||
{
|
||||
throw new Error ("Not implemented");
|
||||
vmch.close();
|
||||
}
|
||||
|
||||
protected final void implConfigureBlocking (boolean blocking)
|
||||
@@ -149,10 +147,10 @@ class PipeImpl extends Pipe
|
||||
|
||||
return vmch.writeGathering(srcs, offset, len);
|
||||
}
|
||||
|
||||
public final int getNativeFD()
|
||||
|
||||
public VMChannel getVMChannel()
|
||||
{
|
||||
return native_fd;
|
||||
return vmch;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,7 +161,9 @@ class PipeImpl extends Pipe
|
||||
throws IOException
|
||||
{
|
||||
super();
|
||||
VMPipe.init (this, provider);
|
||||
VMChannel[] pipe = VMPipe.pipe();
|
||||
sink = new SinkChannelImpl(provider, pipe[0]);
|
||||
source = new SourceChannelImpl(provider, pipe[1]);
|
||||
}
|
||||
|
||||
public Pipe.SinkChannel sink()
|
||||
|
||||
@@ -106,5 +106,6 @@ public abstract class SelectionKeyImpl extends AbstractSelectionKey
|
||||
return impl;
|
||||
}
|
||||
|
||||
/* @deprecated */
|
||||
public abstract int getNativeFD();
|
||||
}
|
||||
|
||||
@@ -54,8 +54,8 @@ import java.util.Set;
|
||||
|
||||
public class SelectorImpl extends AbstractSelector
|
||||
{
|
||||
private Set keys;
|
||||
private Set selected;
|
||||
private Set<SelectionKey> keys;
|
||||
private Set<SelectionKey> selected;
|
||||
|
||||
/**
|
||||
* A dummy object whose monitor regulates access to both our
|
||||
@@ -83,8 +83,8 @@ public class SelectorImpl extends AbstractSelector
|
||||
{
|
||||
super (provider);
|
||||
|
||||
keys = new HashSet ();
|
||||
selected = new HashSet ();
|
||||
keys = new HashSet<SelectionKey> ();
|
||||
selected = new HashSet<SelectionKey> ();
|
||||
}
|
||||
|
||||
protected void finalize() throws Throwable
|
||||
@@ -110,7 +110,7 @@ public class SelectorImpl extends AbstractSelector
|
||||
}
|
||||
}
|
||||
|
||||
public final Set keys()
|
||||
public final Set<SelectionKey> keys()
|
||||
{
|
||||
if (!isOpen())
|
||||
throw new ClosedSelectorException();
|
||||
@@ -136,7 +136,7 @@ public class SelectorImpl extends AbstractSelector
|
||||
{
|
||||
int[] result;
|
||||
int counter = 0;
|
||||
Iterator it = keys.iterator ();
|
||||
Iterator<SelectionKey> it = keys.iterator ();
|
||||
|
||||
// Count the number of file descriptors needed
|
||||
while (it.hasNext ())
|
||||
@@ -253,7 +253,7 @@ public class SelectorImpl extends AbstractSelector
|
||||
selectThread = null;
|
||||
}
|
||||
|
||||
Iterator it = keys.iterator ();
|
||||
Iterator<SelectionKey> it = keys.iterator ();
|
||||
|
||||
while (it.hasNext ())
|
||||
{
|
||||
@@ -317,7 +317,7 @@ public class SelectorImpl extends AbstractSelector
|
||||
}
|
||||
}
|
||||
|
||||
public final Set selectedKeys()
|
||||
public final Set<SelectionKey> selectedKeys()
|
||||
{
|
||||
if (!isOpen())
|
||||
throw new ClosedSelectorException();
|
||||
@@ -350,10 +350,10 @@ public class SelectorImpl extends AbstractSelector
|
||||
|
||||
private final void deregisterCancelledKeys()
|
||||
{
|
||||
Set ckeys = cancelledKeys ();
|
||||
Set<SelectionKey> ckeys = cancelledKeys ();
|
||||
synchronized (ckeys)
|
||||
{
|
||||
Iterator it = ckeys.iterator();
|
||||
Iterator<SelectionKey> it = ckeys.iterator();
|
||||
|
||||
while (it.hasNext ())
|
||||
{
|
||||
|
||||
@@ -37,6 +37,9 @@ exception statement from your version. */
|
||||
|
||||
package gnu.java.nio;
|
||||
|
||||
|
||||
import gnu.classpath.SystemProperties;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.DatagramChannel;
|
||||
import java.nio.channels.Pipe;
|
||||
@@ -47,6 +50,11 @@ import java.nio.channels.spi.SelectorProvider;
|
||||
|
||||
public class SelectorProviderImpl extends SelectorProvider
|
||||
{
|
||||
private static final String SELECTOR_IMPL_KQUEUE = "kqueue";
|
||||
private static final String SELECTOR_IMPL_EPOLL = "epoll";
|
||||
private static final String SELECTOR_IMPL = "gnu.java.nio.selectorImpl";
|
||||
private static boolean epoll_failed = false;
|
||||
|
||||
public SelectorProviderImpl ()
|
||||
{
|
||||
}
|
||||
@@ -66,6 +74,35 @@ public class SelectorProviderImpl extends SelectorProvider
|
||||
public AbstractSelector openSelector ()
|
||||
throws IOException
|
||||
{
|
||||
String selectorImpl = "default";
|
||||
if (KqueueSelectorImpl.kqueue_supported())
|
||||
selectorImpl = SELECTOR_IMPL_KQUEUE;
|
||||
if (EpollSelectorImpl.epoll_supported() && !epoll_failed)
|
||||
selectorImpl = SELECTOR_IMPL_EPOLL;
|
||||
selectorImpl = SystemProperties.getProperty(SELECTOR_IMPL, selectorImpl);
|
||||
|
||||
if (selectorImpl.equals(SELECTOR_IMPL_KQUEUE))
|
||||
return new KqueueSelectorImpl(this);
|
||||
|
||||
if (selectorImpl.equals(SELECTOR_IMPL_EPOLL))
|
||||
{
|
||||
// We jump through these hoops because even though epoll may look
|
||||
// like it's available (sys/epoll.h exists, and you can link against
|
||||
// all the epoll functions) it may not be available in the kernel
|
||||
// (especially 2.4 kernels), meaning you will get ENOSYS at run time.
|
||||
//
|
||||
// Madness!
|
||||
try
|
||||
{
|
||||
return new EpollSelectorImpl(this);
|
||||
}
|
||||
catch (InternalError e)
|
||||
{
|
||||
// epoll_create throws this on ENOSYS.
|
||||
epoll_failed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return new SelectorImpl (this);
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,9 @@ import java.nio.channels.SocketChannel;
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
|
||||
public final class ServerSocketChannelImpl extends ServerSocketChannel
|
||||
implements VMChannelOwner
|
||||
{
|
||||
private VMChannel channel;
|
||||
private NIOServerSocket serverSocket;
|
||||
private boolean connected;
|
||||
|
||||
@@ -56,13 +58,15 @@ public final class ServerSocketChannelImpl extends ServerSocketChannel
|
||||
throws IOException
|
||||
{
|
||||
super (provider);
|
||||
serverSocket = new NIOServerSocket (this);
|
||||
serverSocket = new NIOServerSocket(this);
|
||||
channel = serverSocket.getPlainSocketImpl().getVMChannel();
|
||||
configureBlocking(true);
|
||||
}
|
||||
|
||||
// XXX do we need this?
|
||||
public void finalizer()
|
||||
{
|
||||
if (connected)
|
||||
if (channel.getState().isValid())
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -77,12 +81,12 @@ public final class ServerSocketChannelImpl extends ServerSocketChannel
|
||||
protected void implCloseSelectableChannel () throws IOException
|
||||
{
|
||||
connected = false;
|
||||
serverSocket.close();
|
||||
channel.close();
|
||||
}
|
||||
|
||||
protected void implConfigureBlocking (boolean blocking) throws IOException
|
||||
{
|
||||
serverSocket.setSoTimeout (blocking ? 0 : NIOConstants.DEFAULT_TIMEOUT);
|
||||
channel.setBlocking(blocking);
|
||||
}
|
||||
|
||||
public SocketChannel accept () throws IOException
|
||||
@@ -98,27 +102,28 @@ public final class ServerSocketChannelImpl extends ServerSocketChannel
|
||||
try
|
||||
{
|
||||
begin();
|
||||
serverSocket.getPlainSocketImpl().setInChannelOperation(true);
|
||||
// indicate that a channel is initiating the accept operation
|
||||
// so that the socket ignores the fact that we might be in
|
||||
// non-blocking mode.
|
||||
NIOSocket socket = (NIOSocket) serverSocket.accept();
|
||||
completed = true;
|
||||
return socket.getChannel();
|
||||
}
|
||||
catch (SocketTimeoutException e)
|
||||
{
|
||||
return null;
|
||||
VMChannel client = channel.accept();
|
||||
if (client == null)
|
||||
return null;
|
||||
else
|
||||
{
|
||||
completed = true;
|
||||
return new SocketChannelImpl(provider(), client, false);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
serverSocket.getPlainSocketImpl().setInChannelOperation(false);
|
||||
end (completed);
|
||||
}
|
||||
}
|
||||
|
||||
public ServerSocket socket ()
|
||||
public ServerSocket socket()
|
||||
{
|
||||
return serverSocket;
|
||||
}
|
||||
|
||||
public VMChannel getVMChannel()
|
||||
{
|
||||
return channel;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ exception statement from your version. */
|
||||
|
||||
package gnu.java.nio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.spi.AbstractSelectableChannel;
|
||||
|
||||
public final class ServerSocketChannelSelectionKey
|
||||
@@ -49,10 +50,16 @@ public final class ServerSocketChannelSelectionKey
|
||||
super (channel, selector);
|
||||
}
|
||||
|
||||
// FIXME don't use file descriptor integers
|
||||
public int getNativeFD()
|
||||
{
|
||||
NIOServerSocket socket =
|
||||
(NIOServerSocket) ((ServerSocketChannelImpl) ch).socket();
|
||||
return socket.getPlainSocketImpl().getNativeFD();
|
||||
try
|
||||
{
|
||||
return ((ServerSocketChannelImpl) ch).getVMChannel().getState().getNativeFD();
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
throw new IllegalStateException(ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,15 +39,20 @@ exception statement from your version. */
|
||||
package gnu.java.nio;
|
||||
|
||||
import gnu.java.net.PlainSocketImpl;
|
||||
import gnu.java.net.VMPlainSocketImpl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.SocketException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ReadOnlyBufferException;
|
||||
import java.nio.channels.AlreadyConnectedException;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.ConnectionPendingException;
|
||||
@@ -61,28 +66,57 @@ import java.nio.channels.UnsupportedAddressTypeException;
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
|
||||
public final class SocketChannelImpl extends SocketChannel
|
||||
implements VMChannelOwner
|
||||
{
|
||||
private PlainSocketImpl impl;
|
||||
private VMChannel channel;
|
||||
//private PlainSocketImpl impl;
|
||||
private NIOSocket socket;
|
||||
private boolean connectionPending;
|
||||
private boolean connected;
|
||||
private InetSocketAddress connectAddress;
|
||||
|
||||
public SocketChannelImpl(boolean create) throws IOException
|
||||
{
|
||||
// XXX consider adding security check; this is used by
|
||||
// PlainSocketImpl.
|
||||
this(new SelectorProviderImpl(), create);
|
||||
}
|
||||
|
||||
SocketChannelImpl (SelectorProvider provider)
|
||||
public SocketChannelImpl(VMChannel channel) throws IOException
|
||||
{
|
||||
this(new SelectorProviderImpl(), channel, false);
|
||||
}
|
||||
|
||||
SocketChannelImpl(SelectorProvider provider) throws IOException
|
||||
{
|
||||
this(provider, true);
|
||||
}
|
||||
|
||||
SocketChannelImpl(SelectorProvider provider, boolean create)
|
||||
throws IOException
|
||||
{
|
||||
this(provider, new VMChannel(), create);
|
||||
}
|
||||
|
||||
SocketChannelImpl(SelectorProvider provider, VMChannel channel, boolean create)
|
||||
throws IOException
|
||||
{
|
||||
super (provider);
|
||||
impl = new PlainSocketImpl();
|
||||
socket = new NIOSocket (impl, this);
|
||||
this.channel = channel;
|
||||
if (create)
|
||||
channel.initSocket(true);
|
||||
socket = new NIOSocket(this);
|
||||
configureBlocking(true);
|
||||
}
|
||||
|
||||
SocketChannelImpl (SelectorProvider provider,
|
||||
/*SocketChannelImpl (SelectorProvider provider,
|
||||
NIOSocket socket)
|
||||
throws IOException
|
||||
{
|
||||
super (provider);
|
||||
this.impl = socket.getPlainSocketImpl();
|
||||
this.socket = socket;
|
||||
}
|
||||
}*/
|
||||
|
||||
public void finalizer()
|
||||
{
|
||||
@@ -98,22 +132,27 @@ public final class SocketChannelImpl extends SocketChannel
|
||||
}
|
||||
}
|
||||
|
||||
PlainSocketImpl getPlainSocketImpl()
|
||||
{
|
||||
return impl;
|
||||
}
|
||||
//PlainSocketImpl getPlainSocketImpl()
|
||||
//{
|
||||
// return null; // XXX
|
||||
//}
|
||||
|
||||
protected void implCloseSelectableChannel () throws IOException
|
||||
protected void implCloseSelectableChannel() throws IOException
|
||||
{
|
||||
socket.close();
|
||||
channel.close();
|
||||
}
|
||||
|
||||
protected void implConfigureBlocking (boolean blocking) throws IOException
|
||||
{
|
||||
socket.setSoTimeout (blocking ? 0 : NIOConstants.DEFAULT_TIMEOUT);
|
||||
channel.setBlocking(blocking);
|
||||
}
|
||||
|
||||
public boolean connect (SocketAddress remote) throws IOException
|
||||
{
|
||||
return connect(remote, 0);
|
||||
}
|
||||
|
||||
public boolean connect (SocketAddress remote, int timeout) throws IOException
|
||||
{
|
||||
if (!isOpen())
|
||||
throw new ClosedChannelException();
|
||||
@@ -126,79 +165,52 @@ public final class SocketChannelImpl extends SocketChannel
|
||||
|
||||
if (!(remote instanceof InetSocketAddress))
|
||||
throw new UnsupportedAddressTypeException();
|
||||
|
||||
connectAddress = (InetSocketAddress) remote;
|
||||
|
||||
if (((InetSocketAddress) remote).isUnresolved())
|
||||
if (connectAddress.isUnresolved())
|
||||
throw new UnresolvedAddressException();
|
||||
|
||||
try
|
||||
{
|
||||
socket.getPlainSocketImpl().setInChannelOperation(true);
|
||||
// indicate that a channel is initiating the accept operation
|
||||
// so that the socket ignores the fact that we might be in
|
||||
// non-blocking mode.
|
||||
|
||||
if (isBlocking())
|
||||
{
|
||||
// Do blocking connect.
|
||||
socket.connect (remote);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Do non-blocking connect.
|
||||
try
|
||||
{
|
||||
socket.connect (remote, NIOConstants.DEFAULT_TIMEOUT);
|
||||
return true;
|
||||
}
|
||||
catch (SocketTimeoutException e)
|
||||
{
|
||||
connectionPending = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
socket.getPlainSocketImpl().setInChannelOperation(false);
|
||||
}
|
||||
connected = channel.connect(connectAddress, timeout);
|
||||
connectionPending = !connected;
|
||||
return connected;
|
||||
}
|
||||
|
||||
public boolean finishConnect ()
|
||||
|
||||
public boolean finishConnect()
|
||||
throws IOException
|
||||
{
|
||||
if (!isOpen())
|
||||
throw new ClosedChannelException();
|
||||
|
||||
InetSocketAddress remote = channel.getPeerAddress();
|
||||
if (remote != null)
|
||||
{
|
||||
connectionPending = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!isConnected() && !connectionPending)
|
||||
if (!connectionPending)
|
||||
throw new NoConnectionPendingException();
|
||||
|
||||
if (isConnected())
|
||||
return true;
|
||||
|
||||
// FIXME: Handle blocking/non-blocking mode.
|
||||
|
||||
Selector selector = provider().openSelector();
|
||||
register(selector, SelectionKey.OP_CONNECT);
|
||||
|
||||
if (isBlocking())
|
||||
{
|
||||
selector.select(); // blocking until channel is connected.
|
||||
connectionPending = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int ready = selector.selectNow(); // non-blocking
|
||||
if (ready == 1)
|
||||
{
|
||||
connectionPending = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isConnected ()
|
||||
public boolean isConnected()
|
||||
{
|
||||
return socket.isConnected();
|
||||
// Wait until finishConnect is called before transitioning to
|
||||
// connected.
|
||||
if (connectionPending)
|
||||
return false;
|
||||
try
|
||||
{
|
||||
InetSocketAddress remote = channel.getPeerAddress();
|
||||
return remote != null;
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
ioe.printStackTrace(System.out);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isConnectionPending ()
|
||||
@@ -216,52 +228,7 @@ public final class SocketChannelImpl extends SocketChannel
|
||||
if (!isConnected())
|
||||
throw new NotYetConnectedException();
|
||||
|
||||
byte[] data;
|
||||
int offset = 0;
|
||||
InputStream input = socket.getInputStream();
|
||||
int available = input.available();
|
||||
int len = dst.remaining();
|
||||
|
||||
if ((! isBlocking()) && available == 0)
|
||||
return 0;
|
||||
|
||||
if (dst.hasArray())
|
||||
{
|
||||
offset = dst.arrayOffset() + dst.position();
|
||||
data = dst.array();
|
||||
}
|
||||
else
|
||||
{
|
||||
data = new byte [len];
|
||||
}
|
||||
|
||||
int readBytes = 0;
|
||||
boolean completed = false;
|
||||
|
||||
try
|
||||
{
|
||||
begin();
|
||||
socket.getPlainSocketImpl().setInChannelOperation(true);
|
||||
readBytes = input.read (data, offset, len);
|
||||
completed = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
end (completed);
|
||||
socket.getPlainSocketImpl().setInChannelOperation(false);
|
||||
}
|
||||
|
||||
if (readBytes > 0)
|
||||
if (dst.hasArray())
|
||||
{
|
||||
dst.position (dst.position() + readBytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
dst.put (data, offset, readBytes);
|
||||
}
|
||||
|
||||
return readBytes;
|
||||
return channel.read(dst);
|
||||
}
|
||||
|
||||
public long read (ByteBuffer[] dsts, int offset, int length)
|
||||
@@ -275,61 +242,19 @@ public final class SocketChannelImpl extends SocketChannel
|
||||
|| (length < 0)
|
||||
|| (length > (dsts.length - offset)))
|
||||
throw new IndexOutOfBoundsException();
|
||||
|
||||
long readBytes = 0;
|
||||
|
||||
for (int index = offset; index < length; index++)
|
||||
readBytes += read (dsts [index]);
|
||||
|
||||
return readBytes;
|
||||
|
||||
return channel.readScattering(dsts, offset, length);
|
||||
}
|
||||
|
||||
public int write (ByteBuffer src)
|
||||
throws IOException
|
||||
public int write(ByteBuffer src) throws IOException
|
||||
{
|
||||
if (!isConnected())
|
||||
throw new NotYetConnectedException();
|
||||
|
||||
byte[] data;
|
||||
int offset = 0;
|
||||
int len = src.remaining();
|
||||
|
||||
if (!src.hasArray())
|
||||
{
|
||||
data = new byte [len];
|
||||
src.get (data, 0, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = src.arrayOffset() + src.position();
|
||||
data = src.array();
|
||||
}
|
||||
|
||||
OutputStream output = socket.getOutputStream();
|
||||
boolean completed = false;
|
||||
|
||||
try
|
||||
{
|
||||
begin();
|
||||
socket.getPlainSocketImpl().setInChannelOperation(true);
|
||||
output.write (data, offset, len);
|
||||
completed = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
end (completed);
|
||||
socket.getPlainSocketImpl().setInChannelOperation(false);
|
||||
}
|
||||
|
||||
if (src.hasArray())
|
||||
{
|
||||
src.position (src.position() + len);
|
||||
}
|
||||
|
||||
return len;
|
||||
return channel.write(src);
|
||||
}
|
||||
|
||||
public long write (ByteBuffer[] srcs, int offset, int length)
|
||||
public long write(ByteBuffer[] srcs, int offset, int length)
|
||||
throws IOException
|
||||
{
|
||||
if (!isConnected())
|
||||
@@ -340,12 +265,13 @@ public final class SocketChannelImpl extends SocketChannel
|
||||
|| (length < 0)
|
||||
|| (length > (srcs.length - offset)))
|
||||
throw new IndexOutOfBoundsException();
|
||||
|
||||
long writtenBytes = 0;
|
||||
|
||||
for (int index = offset; index < length; index++)
|
||||
writtenBytes += write (srcs [index]);
|
||||
|
||||
return writtenBytes;
|
||||
return channel.writeGathering(srcs, offset, length);
|
||||
}
|
||||
|
||||
public VMChannel getVMChannel()
|
||||
{
|
||||
// XXX security check?
|
||||
return channel;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ exception statement from your version. */
|
||||
|
||||
package gnu.java.nio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.spi.AbstractSelectableChannel;
|
||||
|
||||
public final class SocketChannelSelectionKey
|
||||
@@ -49,10 +50,16 @@ public final class SocketChannelSelectionKey
|
||||
super (channel, selector);
|
||||
}
|
||||
|
||||
// FIXME don't use file descriptor integers
|
||||
public int getNativeFD()
|
||||
{
|
||||
NIOSocket socket =
|
||||
(NIOSocket) ((SocketChannelImpl) ch).socket();
|
||||
return socket.getPlainSocketImpl().getNativeFD();
|
||||
try
|
||||
{
|
||||
return ((SocketChannelImpl) ch).getVMChannel().getState().getNativeFD();
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
throw new IllegalStateException(ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,8 @@ exception statement from your version. */
|
||||
|
||||
package gnu.java.nio;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* @author Michael Barker <mike@middlesoft.co.uk>
|
||||
@@ -63,7 +65,14 @@ public class SocketChannelSelectionKeyImpl extends SelectionKeyImpl
|
||||
*/
|
||||
public int getNativeFD()
|
||||
{
|
||||
return ch.getPlainSocketImpl().getNativeFD();
|
||||
try
|
||||
{
|
||||
return ch.getVMChannel().getState().getNativeFD();
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
return 0; // FIXME
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/* NativeFD.java -- interface for Channels that have an underlying file descriptor.
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
GNU Classpath is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Classpath 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Classpath; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA.
|
||||
|
||||
Linking this library statically or dynamically with other modules is
|
||||
making a combined work based on this library. Thus, the terms and
|
||||
conditions of the GNU General Public License cover the whole
|
||||
combination.
|
||||
|
||||
As a special exception, the copyright holders of this library give you
|
||||
permission to link this library with independent modules to produce an
|
||||
executable, regardless of the license terms of these independent
|
||||
modules, and to copy and distribute the resulting executable under
|
||||
terms of your choice, provided that you also meet, for each linked
|
||||
independent module, the terms and conditions of the license of that
|
||||
module. An independent module is a module which is not derived from
|
||||
or based on this library. If you modify this library, you may extend
|
||||
this exception to your version of the library, but you are not
|
||||
obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. */
|
||||
|
||||
|
||||
package gnu.java.nio;
|
||||
|
||||
/**
|
||||
* This interface is meant to be implemented by any {@link Channel}
|
||||
* implementation we support that uses a platform-specific {@link VMChannel}
|
||||
* at their core. This is primarily used by {@link Selector} implementations,
|
||||
* for easier access to the native state.
|
||||
*
|
||||
* @author Casey Marshall (csm@gnu.org)
|
||||
*/
|
||||
interface VMChannelOwner
|
||||
{
|
||||
/**
|
||||
* Return the underlying platform-specific Channel instance.
|
||||
*
|
||||
* @return The platform channel object.
|
||||
*/
|
||||
VMChannel getVMChannel();
|
||||
}
|
||||
Reference in New Issue
Block a user