Merged gcj-eclipse branch to trunk.

From-SVN: r120621
This commit is contained in:
Tom Tromey
2007-01-09 19:58:05 +00:00
parent c648dedbde
commit 97b8365caf
17478 changed files with 606493 additions and 100744 deletions
@@ -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);
}
@@ -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);
}
+16 -13
View File
@@ -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.
}
}
+17 -17
View File
@@ -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();
}