Hi,

My name is Mike Barker.  I am interesting in contributing to the GNU
Classpath project.  As a start I have looked the NIO implemenation with
regards to Channels (specifically SocketChannel).  

Attached to this mail is a patch that adds support for configuring a
socket to be non-blocking and uses readv and writev system calls to
support native scatter/gather operations.  Native access is through a
VMChannel.java class.  This class could also be added to other Channel
types to implement native scatter/gather I/O across the board.

The patch is not quite complete.  It passes the Mauve tests, but
requires a more comprehensive set of tests (e.g. testing readv/writev
and different types of ByteBuffer, direct & mapped).  However if what I
doing looks reasonably sane, I can continue in order to provide a more
complete patch.  Comments, criticism, etc. is welcome.

Quick question:
I understand the info on the Wiki around developer tainting, which is OK
as I have not studied the Java sources.  What about black-box testing of
the functionality of the JVM?  Does doing this taint the developer?

Regards,
Mike Barker.
Index: .settings/org.eclipse.jdt.core.prefs
===================================================================
RCS file: /cvsroot/classpath/classpath/.settings/org.eclipse.jdt.core.prefs,v
retrieving revision 1.5
diff -u -r1.5 org.eclipse.jdt.core.prefs
--- .settings/org.eclipse.jdt.core.prefs	14 Sep 2005 01:33:27 -0000	1.5
+++ .settings/org.eclipse.jdt.core.prefs	11 Jan 2006 22:09:39 -0000
@@ -1,4 +1,4 @@
-#Tue Sep 13 16:15:04 MDT 2005
+#Thu Dec 22 16:04:11 GMT 2005
 eclipse.preferences.version=1
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
 org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.4
@@ -15,7 +15,7 @@
 org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
 org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
 org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
-org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning
 org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
 org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
 org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
@@ -72,6 +72,7 @@
 org.eclipse.jdt.core.formatter.alignment_for_binary_expression=18
 org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
 org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=82
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
 org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=18
 org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=18
@@ -302,3 +303,4 @@
 org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
 org.eclipse.jdt.core.formatter.tabulation.char=space
 org.eclipse.jdt.core.formatter.tabulation.size=2
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
Index: .settings/org.eclipse.jdt.ui.prefs
===================================================================
RCS file: /cvsroot/classpath/classpath/.settings/org.eclipse.jdt.ui.prefs,v
retrieving revision 1.4
diff -u -r1.4 org.eclipse.jdt.ui.prefs
--- .settings/org.eclipse.jdt.ui.prefs	18 Sep 2005 04:19:36 -0000	1.4
+++ .settings/org.eclipse.jdt.ui.prefs	11 Jan 2006 22:09:39 -0000
@@ -1,4 +1,4 @@
-#Sat Sep 17 22:04:29 MDT 2005
+#Thu Dec 22 16:04:10 GMT 2005
 eclipse.preferences.version=1
 formatter_settings_version=8
 internal.default.compliance=user
Index: gnu/java/nio/SelectorImpl.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/nio/SelectorImpl.java,v
retrieving revision 1.21
diff -u -r1.21 SelectorImpl.java
--- gnu/java/nio/SelectorImpl.java	27 Dec 2005 08:32:12 -0000	1.21
+++ gnu/java/nio/SelectorImpl.java	11 Jan 2006 22:09:41 -0000
@@ -379,6 +379,8 @@
       result = new DatagramChannelSelectionKey (ch, this);
     else if (ch instanceof ServerSocketChannelImpl)
       result = new ServerSocketChannelSelectionKey (ch, this);
+    else if (ch instanceof gnu.java.nio.channels.SocketChannelImpl)
+      result = new gnu.java.nio.channels.SocketChannelSelectionKeyImpl((gnu.java.nio.channels.SocketChannelImpl)ch, this);
     else
       throw new InternalError ("No known channel type");
 
Index: gnu/java/nio/SelectorProviderImpl.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/nio/SelectorProviderImpl.java,v
retrieving revision 1.8
diff -u -r1.8 SelectorProviderImpl.java
--- gnu/java/nio/SelectorProviderImpl.java	2 Jul 2005 20:32:13 -0000	1.8
+++ gnu/java/nio/SelectorProviderImpl.java	11 Jan 2006 22:09:41 -0000
@@ -78,6 +78,7 @@
   public SocketChannel openSocketChannel ()
     throws IOException
   {
-    return new SocketChannelImpl (this);
+    //return new SocketChannelImpl (this);
+    return new gnu.java.nio.channels.SocketChannelImpl (this);
   }
 }
Index: gnu/java/nio/ServerSocketChannelImpl.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/nio/ServerSocketChannelImpl.java,v
retrieving revision 1.14
diff -u -r1.14 ServerSocketChannelImpl.java
--- gnu/java/nio/ServerSocketChannelImpl.java	2 Jul 2005 20:32:13 -0000	1.14
+++ gnu/java/nio/ServerSocketChannelImpl.java	11 Jan 2006 22:09:42 -0000
@@ -102,7 +102,7 @@
           // 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();
+        gnu.java.nio.channels.NIOSocket socket = (gnu.java.nio.channels.NIOSocket) serverSocket.accept();
         completed = true;
         return socket.getChannel();
       }
Index: include/Makefile.am
===================================================================
RCS file: /cvsroot/classpath/classpath/include/Makefile.am,v
retrieving revision 1.52
diff -u -r1.52 Makefile.am
--- include/Makefile.am	4 Jan 2006 16:37:55 -0000	1.52
+++ include/Makefile.am	11 Jan 2006 22:09:43 -0000
@@ -122,6 +122,7 @@
 $(top_srcdir)/include/gnu_java_nio_VMPipe.h \
 $(top_srcdir)/include/gnu_java_nio_VMSelector.h \
 $(top_srcdir)/include/gnu_java_nio_channels_FileChannelImpl.h \
+$(top_srcdir)/include/gnu_java_nio_channels_VMChannel.h \
 $(top_srcdir)/include/gnu_java_nio_charset_iconv_IconvEncoder.h \
 $(top_srcdir)/include/gnu_java_nio_charset_iconv_IconvDecoder.h \
 $(top_srcdir)/include/java_io_VMFile.h \
@@ -200,6 +201,8 @@
 	$(JAVAH) -o $@ java.nio.MappedByteBufferImpl
 $(top_srcdir)/include/gnu_java_nio_channels_FileChannelImpl.h: $(top_srcdir)/gnu/java/nio/channels/FileChannelImpl.java
 	$(JAVAH) -o $@ gnu.java.nio.channels.FileChannelImpl
+$(top_srcdir)/include/gnu_java_nio_channels_FileChannelImpl.h: $(top_srcdir)/gnu/java/nio/channels/VMChannel.java
+	$(JAVAH) -o $@ gnu.java.nio.channels.VMChannel
 $(top_srcdir)/include/gnu_java_nio_charset_iconv_IconvDecoder.h: $(top_srcdir)/gnu/java/nio/charset/iconv/IconvDecoder.java
 	$(JAVAH) -o $@ gnu.java.nio.charset.iconv.IconvDecoder
 $(top_srcdir)/include/gnu_java_nio_charset_iconv_IconvEncoder.h: $(top_srcdir)/gnu/java/nio/charset/iconv/IconvEncoder.java
Index: native/jni/java-nio/Makefile.am
===================================================================
RCS file: /cvsroot/classpath/classpath/native/jni/java-nio/Makefile.am,v
retrieving revision 1.19
diff -u -r1.19 Makefile.am
--- native/jni/java-nio/Makefile.am	23 Oct 2005 16:59:08 -0000	1.19
+++ native/jni/java-nio/Makefile.am	11 Jan 2006 22:09:53 -0000
@@ -5,8 +5,10 @@
 			gnu_java_nio_channels_FileChannelImpl.c \
 			gnu_java_nio_charset_iconv_IconvDecoder.c \
 			gnu_java_nio_charset_iconv_IconvEncoder.c \
+			gnu_java_nio_channels_VMChannel.c \
 			java_nio_MappedByteBufferImpl.c \
-			java_nio_VMDirectByteBuffer.c
+			java_nio_VMDirectByteBuffer.c 
+			
 
 libjavanio_la_LIBADD = $(top_builddir)/native/jni/classpath/jcl.lo \
 		       $(LTLIBICONV) 
Index: gnu/java/nio/channels/NIOSocket.java
===================================================================
RCS file: gnu/java/nio/channels/NIOSocket.java
diff -N gnu/java/nio/channels/NIOSocket.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gnu/java/nio/channels/NIOSocket.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,79 @@
+/* NIOSocket.java -- Wrapper socket implemenation class.
+   Copyright (C) 2003 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.channels;
+
+import gnu.java.net.PlainSocketImpl;
+import gnu.java.nio.channels.SocketChannelImpl;
+
+import java.io.IOException;
+import java.net.Socket;
+import java.nio.channels.SocketChannel;
+
+/**
+ * @author Michael Koch
+ */
+public final class NIOSocket extends Socket
+{
+  private PlainSocketImpl impl;
+  private SocketChannelImpl channel;
+    
+  protected NIOSocket (PlainSocketImpl impl, SocketChannelImpl channel)
+    throws IOException
+  {
+    super (impl);
+    this.impl = impl;
+    this.channel = channel;
+  }
+
+  public final PlainSocketImpl getPlainSocketImpl()
+  {
+    return impl;
+  }
+
+  final void setChannel (SocketChannelImpl channel)
+  {
+    this.impl = channel.getPlainSocketImpl();
+    this.channel = channel;
+  }
+  
+  public final SocketChannel getChannel()
+  {
+    return channel;
+  }
+}
Index: gnu/java/nio/channels/SocketChannelImpl.java
===================================================================
RCS file: gnu/java/nio/channels/SocketChannelImpl.java
diff -N gnu/java/nio/channels/SocketChannelImpl.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gnu/java/nio/channels/SocketChannelImpl.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,285 @@
+/* PosixSocketChannelImpl.java -- Non-blocking enable socket channel
+   Copyright (C) 2005 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.channels;
+
+import gnu.java.net.PlainSocketImpl;
+import gnu.java.nio.NIOConstants;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketTimeoutException;
+import java.nio.ByteBuffer;
+import java.nio.channels.AlreadyConnectedException;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.ConnectionPendingException;
+import java.nio.channels.NoConnectionPendingException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.SocketChannel;
+import java.nio.channels.UnresolvedAddressException;
+import java.nio.channels.UnsupportedAddressTypeException;
+import java.nio.channels.spi.SelectorProvider;
+
+/**
+ * @author Michael Barker
+ *
+ */
+public class SocketChannelImpl extends SocketChannel
+{
+  private VMChannel vmch;
+  private PlainSocketImpl sImpl;
+  private Socket socket;
+  private boolean connectionPending;
+  
+  /**
+   * @param provider
+   * @throws IOException 
+   */
+  public SocketChannelImpl(SelectorProvider provider) 
+    throws IOException
+  {
+    super(provider);
+    this.vmch = new VMChannel();
+    this.sImpl = new PlainSocketImpl();
+    this.socket = new NIOSocket(sImpl, this);
+  }
+  
+  /* (non-Javadoc)
+   * @see java.nio.channels.SocketChannel#read(java.nio.ByteBuffer)
+   */
+  public int read(ByteBuffer dst) 
+    throws IOException
+  {
+    return vmch.read(getFd(), dst);
+  }
+  
+
+  /* (non-Javadoc)
+   * @see java.nio.channels.SocketChannel#read(java.nio.ByteBuffer[], int, int)
+   */
+  public long read(ByteBuffer[] dsts, int offset, int length) 
+    throws IOException
+  {
+    return vmch.readScattering(getFd(), dsts, offset, length);
+  }
+  
+  
+  /* (non-Javadoc)
+   * @see java.nio.channels.SocketChannel#connect(java.net.SocketAddress)
+   */
+  public boolean connect(SocketAddress remote) 
+    throws IOException
+  {
+    if (!isOpen())
+      throw new ClosedChannelException();
+    
+    if (isConnected())
+      throw new AlreadyConnectedException();
+
+    if (connectionPending)
+      throw new ConnectionPendingException();
+
+    if (!(remote instanceof InetSocketAddress))
+      throw new UnsupportedAddressTypeException();
+
+    if (((InetSocketAddress) remote).isUnresolved())
+      throw new UnresolvedAddressException();
+    
+    try
+      {
+        sImpl.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
+      {
+        sImpl.setInChannelOperation(false);
+      }
+  }
+
+  /* (non-Javadoc)
+   * @see java.nio.channels.SocketChannel#finishConnect()
+   */
+  public boolean finishConnect() 
+    throws IOException
+  {
+    if (!isOpen())
+      throw new ClosedChannelException();
+    
+    if (!isConnected() && !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;
+  }
+
+  /* (non-Javadoc)
+   * @see java.nio.channels.SocketChannel#isConnected()
+   */
+  public boolean isConnected()
+  {
+    return socket.isConnected();
+  }
+
+  /* (non-Javadoc)
+   * @see java.nio.channels.SocketChannel#isConnectionPending()
+   */
+  public boolean isConnectionPending()
+  {
+    return connectionPending;
+  }
+
+
+  /* (non-Javadoc)
+   * @see java.nio.channels.SocketChannel#socket()
+   */
+  public Socket socket()
+  {
+    return socket;
+  }
+
+  /* (non-Javadoc)
+   * @see java.nio.channels.SocketChannel#write(java.nio.ByteBuffer)
+   */
+  public int write(ByteBuffer src) 
+    throws IOException
+  {
+    return vmch.write(getFd(), src);
+  }
+
+  /* (non-Javadoc)
+   * @see java.nio.channels.SocketChannel#write(java.nio.ByteBuffer[], int, int)
+   */
+  public long write(ByteBuffer[] srcs, int offset, int length) 
+    throws IOException
+  {
+    return vmch.writeGathering(getFd(), srcs, offset, length);
+  }
+
+  /* (non-Javadoc)
+   * @see java.nio.channels.spi.AbstractSelectableChannel#implCloseSelectableChannel()
+   */
+  protected void implCloseSelectableChannel() 
+    throws IOException
+  {
+    socket.close();
+  }
+  
+
+  /* (non-Javadoc)
+   * @see java.nio.channels.spi.AbstractSelectableChannel#implConfigureBlocking(boolean)
+   */
+  protected void implConfigureBlocking(boolean blocking) 
+    throws IOException
+  {
+    vmch.setBlocking(getFd(), blocking);
+  }
+  
+  public int getFd()
+  {
+    return sImpl.getNativeFD();
+  }
+
+
+  /**
+   * @return The socket implemenation
+   */
+  public PlainSocketImpl getPlainSocketImpl()
+  {
+    return sImpl;
+  }
+  
+  public void finalizer()
+  {
+    if (isConnected())
+      {
+        try
+          {
+            close ();
+          }
+        catch (Exception e)
+          {
+          }
+      }
+  }  
+
+}
Index: gnu/java/nio/channels/SocketChannelSelectionKeyImpl.java
===================================================================
RCS file: gnu/java/nio/channels/SocketChannelSelectionKeyImpl.java
diff -N gnu/java/nio/channels/SocketChannelSelectionKeyImpl.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gnu/java/nio/channels/SocketChannelSelectionKeyImpl.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,71 @@
+/* SocketChannelSelectionKey.java -- Selection key for Socket Channel
+   Copyright (C) 2005 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.channels;
+
+import gnu.java.nio.SelectionKeyImpl;
+import gnu.java.nio.SelectorImpl;
+
+/**
+ * @author mike
+ *
+ */
+public class SocketChannelSelectionKeyImpl extends SelectionKeyImpl
+{
+
+  SocketChannelImpl ch;
+  
+  /**
+   * @param ch
+   * @param impl
+   */
+  public SocketChannelSelectionKeyImpl(SocketChannelImpl ch, SelectorImpl impl)
+  {
+    super(ch, impl);
+    this.ch = (SocketChannelImpl) ch;
+  }
+
+  /* (non-Javadoc)
+   * @see gnu.java.nio.SelectionKeyImpl#getNativeFD()
+   */
+  public int getNativeFD()
+  {
+    return ch.getFd();
+  }
+
+}
Index: gnu/java/nio/channels/VMChannel.java
===================================================================
RCS file: gnu/java/nio/channels/VMChannel.java
diff -N gnu/java/nio/channels/VMChannel.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gnu/java/nio/channels/VMChannel.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,124 @@
+/* VMChannel.java -- Native interface suppling channel operations.
+   Copyright (C) 2005 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.channels;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * @author mike
+ *
+ */
+public class VMChannel
+{
+  
+  static
+  {
+    initIDs();
+  }
+  
+  /**
+   * Set the file descriptor to have the required blocking
+   * setting.
+   * 
+   * @param fd
+   * @param blocking
+   */
+  native void setBlocking(int fd, boolean blocking);
+  
+
+  /**
+   * Reads a byte buffer directly using the supplied file descriptor.
+   * Assumes that the buffer is a DirectBuffer.
+   * 
+   * @param fd Native file descriptor to read from.
+   * @param dst Direct Byte Buffer to read to.
+   * @return Number of bytes read.
+   * @throws IOException If an error occurs or dst is not a direct buffers. 
+   */
+  native int read(int fd, ByteBuffer dst)
+    throws IOException;
+  
+  /**
+   * Reads into byte buffers directly using the supplied file descriptor.
+   * Assumes that the buffer list contains DirectBuffers.  Will perform a
+   * scattering read.
+   * 
+   * @param fd Native file descriptor to read from.
+   * @param dsts An array direct byte buffers.
+   * @param offset Index of the first buffer to read to.
+   * @param length The number of buffers to read to.
+   * @return Number of bytes read.
+   * @throws IOException If an error occurs or the dsts are not direct buffers. 
+   */
+  native long readScattering(int fd, ByteBuffer[] dsts, int offset, int length)
+    throws IOException;
+
+  
+  /**
+   * Writes from a direct byte bufer using the supplied file descriptor.
+   * Assumes the buffer is a DirectBuffer.
+   * 
+   * @param fd
+   * @param src
+   * @return Number of bytes written.
+   * @throws IOException
+   */
+  native int write(int fd, ByteBuffer src)
+    throws IOException;
+
+  /**
+   * Writes from byte buffers directly using the supplied file descriptor.
+   * Assumes the that buffer list constains DirectBuffers.  Will perform
+   * as gathering write.
+   * 
+   * @param fd
+   * @param srcs
+   * @param offset
+   * @param length
+   * @return Number of bytes written.
+   * @throws IOException
+   */
+  native long writeGathering(int fd, ByteBuffer[] srcs, int offset, int length)
+    throws IOException;
+  
+  
+  private native static void initIDs();
+
+}
Index: include/gnu_java_nio_channels_VMChannel.h
===================================================================
RCS file: include/gnu_java_nio_channels_VMChannel.h
diff -N include/gnu_java_nio_channels_VMChannel.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ include/gnu_java_nio_channels_VMChannel.h	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,24 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+
+#ifndef __gnu_java_nio_channels_VMChannel__
+#define __gnu_java_nio_channels_VMChannel__
+
+#include <jni.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+JNIEXPORT void JNICALL Java_gnu_java_nio_channels_VMChannel_setBlocking (JNIEnv *env, jobject, jint, jboolean);
+JNIEXPORT jint JNICALL Java_gnu_java_nio_channels_VMChannel_read (JNIEnv *env, jobject, jint, jobject);
+JNIEXPORT jlong JNICALL Java_gnu_java_nio_channels_VMChannel_readScattering (JNIEnv *env, jobject, jint, jobjectArray, jint, jint);
+JNIEXPORT jint JNICALL Java_gnu_java_nio_channels_VMChannel_write (JNIEnv *env, jobject, jint, jobject);
+JNIEXPORT jlong JNICALL Java_gnu_java_nio_channels_VMChannel_writeGathering (JNIEnv *env, jobject, jint, jobjectArray, jint, jint);
+JNIEXPORT void JNICALL Java_gnu_java_nio_channels_VMChannel_initIDs (JNIEnv *env, jclass);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gnu_java_nio_channels_VMChannel__ */
Index: native/jni/java-nio/gnu_java_nio_channels_VMChannel.c
===================================================================
RCS file: native/jni/java-nio/gnu_java_nio_channels_VMChannel.c
diff -N native/jni/java-nio/gnu_java_nio_channels_VMChannel.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ native/jni/java-nio/gnu_java_nio_channels_VMChannel.c	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,508 @@
+/* gnu_java_nio_channels_VMChannel.c -
+   Copyright (C) 2003, 2004, 2005, 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. */
+
+
+#include <config.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/uio.h>
+#include <string.h>
+
+#include <jni.h>
+#include <jcl.h>
+
+#include "gnu_java_nio_channels_VMChannel.h"
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif /* HAVE_FCNTL_H */
+
+#define IO_EXCEPTION "java/io/IOException"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* FIXME: This can't be right.  Need converter macros */
+#define CONVERT_JINT_TO_INT(x) ((int)(x & 0xFFFFFFFF))
+#define CONVERT_INT_TO_JINT(x) ((int)(x & 0xFFFFFFFF))
+
+/* FIXME: This can't be right.  Need converter macros. */
+#define CONVERT_SSIZE_T_TO_JINT(x) ((jint)(x & 0xFFFFFFFF))
+#define CONVERT_JINT_TO_SSIZE_T(x) (x)
+
+static jfieldID address_fid;
+static jmethodID get_position_mid;
+static jmethodID set_position_mid;
+static jmethodID get_limit_mid;
+static jmethodID set_limit_mid;
+static jmethodID has_array_mid;
+static jmethodID array_mid;
+static jmethodID array_offset_mid;
+/*
+static jmethodID put_mid;
+static jmethodID get_mid;
+*/
+
+jmethodID
+get_method_id(JNIEnv *env,  jclass clazz, const char *name, 
+	          const char *sig)
+{
+  jmethodID mid = (*env)->GetMethodID(env, clazz, name, sig);
+  if (mid == NULL)
+    {
+  	  JCL_ThrowException(env, "java/lang/InternalError", name);
+      return NULL;
+    }
+  
+  return mid;
+}
+
+enum JCL_buffer_type { DIRECT, ARRAY, UNKNOWN };
+
+struct JCL_buffer
+{
+  enum JCL_buffer_type type;
+  jbyte *ptr;
+  jbyteArray array;
+  jobject bbuf;
+  jint offset;
+  jint position;
+  jint limit;
+  jint count;
+};
+
+int
+JCL_init_buffer(JNIEnv *env, struct JCL_buffer *buf, jobject bbuf)
+{
+  jobject address = (*env)->GetObjectField(env, bbuf, address_fid);
+  
+  buf->position = (*env)->CallIntMethod(env, bbuf, get_position_mid);
+  buf->limit = (*env)->CallIntMethod(env, bbuf, get_limit_mid);
+  buf->bbuf = bbuf;
+  buf->offset = 0;
+  buf->array = NULL;
+  buf->count = 0;
+  buf->type = UNKNOWN;
+    
+  if (address != NULL)
+    {
+      buf->ptr = (jbyte *) JCL_GetRawData(env, address);
+      buf->type = DIRECT;
+    }
+  else
+    {
+      jboolean has_array;
+      
+      has_array = (*env)->CallBooleanMethod(env, bbuf, has_array_mid);
+      if (has_array == JNI_TRUE)
+        {
+          buf->offset = (*env)->CallIntMethod(env, bbuf, array_offset_mid);
+          buf->array = (*env)->CallObjectMethod(env, bbuf, array_mid);
+          buf->ptr = (*env)->GetByteArrayElements(env, buf->array, 0);
+          buf->type = ARRAY;
+        }
+      else
+        {
+          return -1;
+        }
+    }
+      
+  return 0;
+}
+
+void
+JCL_release_buffer(JNIEnv *env, struct JCL_buffer *buf, jint action)
+{
+  /* Set the position to the appropriate value */
+  if (buf->count > 0)
+    (*env)->CallObjectMethod(env, buf->bbuf, set_position_mid, 
+                             buf->position + buf->count);
+    
+  switch (buf->type)
+    {
+    case DIRECT:
+      break;
+    case ARRAY:
+      (*env)->ReleaseByteArrayElements(env, buf->array, buf->ptr, action);
+      break;
+    case UNKNOWN:
+      /* TODO: Handle buffers that are not direct or array backed */
+      break;
+    }
+}
+
+
+JNIEXPORT void JNICALL 
+Java_gnu_java_nio_channels_VMChannel_initIDs  (JNIEnv *env, 
+	jclass clazz __attribute__ ((__unused__)))
+{
+  jclass bufferClass = JCL_FindClass(env, "java/nio/Buffer");
+  jclass byteBufferClass = JCL_FindClass(env, "java/nio/ByteBuffer");
+  
+  address_fid = (*env)->GetFieldID(env, bufferClass, "address", 
+                                   "Lgnu/classpath/Pointer;");
+  if (address_fid == NULL)
+    {
+  	  JCL_ThrowException(env, "java/lang/InternalError", 
+  	  	"Unable to find internal field");
+      return;
+    }
+  
+  get_position_mid = get_method_id(env, bufferClass, "position", "()I");
+  set_position_mid = get_method_id(env, bufferClass, "position", 
+                                   "(I)Ljava/nio/Buffer;");
+  get_limit_mid = get_method_id(env, bufferClass, "limit", "()I");
+  set_limit_mid = get_method_id(env, bufferClass, "limit", 
+                                "(I)Ljava/nio/Buffer;");
+  has_array_mid = get_method_id(env, byteBufferClass, "hasArray", "()Z");
+  array_mid = get_method_id(env, byteBufferClass, "array", "()[B");
+  array_offset_mid = get_method_id(env, byteBufferClass, "arrayOffset", "()I");
+  /*
+  get_mid = get_method_id(env, byteBufferClass, "get", 
+                          "([B)Ljava.nio.ByteBuffer;");
+  put_mid = get_method_id(env, byteBufferClass, "put", 
+                          "([B)Ljava.nio.ByteBuffer;");
+  */
+}
+
+JNIEXPORT void JNICALL 
+Java_gnu_java_nio_channels_VMChannel_setBlocking (JNIEnv *env, 
+	jobject o __attribute__ ((__unused__)), 
+	jint fd, 
+	jboolean blocking)
+{
+  int opts;
+  
+  opts = fcntl(fd, F_GETFL);
+  if (opts < 0)
+    {
+      JCL_ThrowException(env, IO_EXCEPTION, 
+        "Failed to get flags for file desriptor");
+      return;
+    }
+  
+  if (blocking)
+    opts |= O_NONBLOCK;
+  else
+    opts &= ~(O_NONBLOCK);
+  
+  opts = fcntl(fd, F_SETFL, opts);
+  
+  if (opts < 0)
+    {
+      JCL_ThrowException(env, IO_EXCEPTION, 
+        "Failed to set flags for file desriptor");
+      return;
+    }  
+}
+
+
+JNIEXPORT jint JNICALL 
+Java_gnu_java_nio_channels_VMChannel_read (JNIEnv *env, 
+	jobject o __attribute__ ((__unused__)), 
+	jint fd, 
+	jobject bbuf)
+{
+  jint len;
+  ssize_t result;
+  struct JCL_buffer buf;
+  
+  if (JCL_init_buffer(env, &buf, bbuf) < 0)
+    {
+      /* TODO: Rethrown exception */
+      JCL_ThrowException (env, IO_EXCEPTION, "Buffer initialisation failed");
+      return -1;
+    }
+  
+  len = buf.limit - buf.position;
+  
+  result = read(fd, &(buf.ptr[buf.position + buf.offset]), len);
+  buf.count = result;
+  
+  if (result == 0)
+    result = -1; /* End Of File */
+  else if (result == -1)
+    {
+      buf.count = 0;
+      if (errno == EAGAIN) /* Non-blocking */
+        result = 0;
+      else
+        {
+          JCL_release_buffer(env, &buf, JNI_ABORT);
+      	  JCL_ThrowException (env, IO_EXCEPTION, strerror(errno));
+      	  return -1;
+        }
+    }
+  else 
+    
+  JCL_release_buffer(env, &buf, JNI_COMMIT);
+  
+  return result;
+}
+
+JNIEXPORT jint JNICALL 
+Java_gnu_java_nio_channels_VMChannel_write (JNIEnv *env, 
+	jobject o __attribute__ ((__unused__)), 
+	jint fd, 
+	jobject bbuf)
+{
+  jint len;
+  ssize_t result;
+  struct JCL_buffer buf;
+  
+  if (JCL_init_buffer(env, &buf, bbuf) < 0)
+    {
+      /* TODO: Rethrown exception */
+      JCL_ThrowException (env, IO_EXCEPTION, "Buffer initialisation failed");
+      return -1;
+    }
+  
+  len = buf.limit - buf.position;
+  
+  result = write(fd, &(buf.ptr[buf.offset]), len);
+  buf.count = result;
+  
+  if (result == -1)
+    {
+      if (errno == EAGAIN) /* Non-blocking */
+          result = 0;
+      else
+        {
+          JCL_release_buffer(env, &buf, JNI_ABORT);
+          JCL_ThrowException(env, IO_EXCEPTION, strerror(errno));
+          return -1;
+        }
+    }
+    
+  JCL_release_buffer(env, &buf, JNI_ABORT);
+  
+  return result;  
+}
+
+
+/*
+ * Implementation of a scattering read.  Will use the appropriate
+ * vector based read call (currently readv on Linux).
+ * 
+ * This has a limit to the number of buffers that will be read.  It
+ * will not make muliple readv calls.  This is to ensure that operations 
+ * are atomic.  Currently it is limited to sysconf(_SC_IOV_MAX) which
+ * is 1024 (according to the man page).
+ */
+JNIEXPORT jlong JNICALL 
+Java_gnu_java_nio_channels_VMChannel_readScattering (JNIEnv *env, 
+	jobject o __attribute__ ((__unused__)), 
+	jint fd, 
+	jobjectArray bbufs, 
+	jint offset, 
+	jint length)
+{
+  /* FIXME: This is not portable */
+  const jint JCL_IOV_MAX = CONVERT_INT_TO_JINT(sysconf(_SC_IOV_MAX));
+  jint i;
+  jboolean is_error = JNI_FALSE;
+  char *error_msg;
+  struct iovec *buffers = NULL;
+  struct JCL_buffer *bi_list = NULL;
+  ssize_t result;
+  jint vec_len = length < JCL_IOV_MAX ? length : JCL_IOV_MAX;
+  jlong bytes_read = 0;      
+  
+  buffers = JCL_malloc(env, vec_len * sizeof(struct iovec));
+  bi_list = JCL_malloc(env, vec_len * sizeof(struct JCL_buffer));
+  
+  /* Build the vector of buffers to read into */
+  for (i = 0; i < vec_len; i++)
+    {
+      struct JCL_buffer buf = bi_list[i];
+      jobject bbuf = (*env)->GetObjectArrayElement(env, bbufs, offset + i);
+      
+      JCL_init_buffer(env, &buf, bbuf); 
+      
+      buffers[i].iov_base = &(buf.ptr[buf.position + buf.offset]);
+      buffers[i].iov_len = buf.limit - buf.position;
+    }
+    
+  /* Work the scattering magic */
+  result = readv(fd, buffers, vec_len);
+  /* XXX: Convert ssize_t to a jlong */
+  bytes_read = result;
+  
+  /* Handle the response */
+  if (result < 0)
+    {
+      if (errno == EAGAIN) /* Non blocking */
+        result = 0;
+      else
+        {
+          is_error = JNI_TRUE;
+          error_msg = strerror(errno);
+        }
+      bytes_read = 0;
+    }
+  else if (result == 0) /* EOF */
+    {
+      result = -1;
+    }
+    
+  /* Update all of the bbufs with the approriate information */
+  for (i = 0; i < vec_len; i++)
+    {
+      struct JCL_buffer buf = bi_list[i];
+
+      if (bytes_read > (buf.limit - buf.position))
+        buf.count = (buf.limit - buf.position);
+      else
+        buf.count = bytes_read;
+        
+      bytes_read -= buf.count;
+      
+      JCL_release_buffer(env, &buf, JNI_COMMIT);      
+    }
+        
+
+  /* A GC, a GC, my kingdom for a GC */
+  JCL_free(env, buffers);
+  JCL_free(env, bi_list);
+      
+  if (is_error == JNI_TRUE)
+    {
+      JCL_ThrowException(env, IO_EXCEPTION, error_msg);
+      return -1;
+    }
+    
+  /* XXX: Convert ssize_t to a jlong */
+  return result;
+}
+
+/*
+ * Implementation of a gathering write.  Will use the appropriate
+ * vector based read call (currently readv on Linux).
+ * 
+ * This has a limit to the number of buffers that will be read.  It
+ * will not make muliple readv calls.  This is to ensure that operations 
+ * are atomic.  Currently it is limited to sysconf(_SC_IOV_MAX) which
+ * is 1024 (according to the man page).
+ */
+JNIEXPORT jlong JNICALL 
+Java_gnu_java_nio_channels_VMChannel_writeGathering (JNIEnv *env, 
+	jobject o __attribute__ ((__unused__)), 
+	jint fd, 
+	jobjectArray bbufs, 
+	jint offset, 
+	jint length)
+{
+  /* FIXME: This is not portable */
+  const jint JCL_IOV_MAX = CONVERT_INT_TO_JINT(sysconf(_SC_IOV_MAX));
+  int i;
+  jboolean is_error = JNI_FALSE;
+  char *error_msg;
+  struct iovec *buffers = NULL;
+  struct JCL_buffer *bi_list = NULL;
+  ssize_t result;
+  jint vec_len = length < JCL_IOV_MAX ? length : JCL_IOV_MAX;
+  jlong bytes_written;
+  
+  buffers = JCL_malloc(env, vec_len * sizeof (struct iovec));
+  bi_list = JCL_malloc(env, vec_len * sizeof(jbyte *));
+  
+  /* Build the vector of buffers to read into */
+  for (i = 0; i < vec_len; i++)
+    {
+      struct JCL_buffer buf = bi_list[i];
+      jobject bbuf = (*env)->GetObjectArrayElement(env, bbufs, offset + i);
+      
+      JCL_init_buffer(env, &buf, bbuf); 
+      
+      buffers[i].iov_base = &(buf.ptr[buf.position + buf.offset]);
+      buffers[i].iov_len = buf.limit - buf.position;
+    }
+    
+  /* Work the gathering magic */
+  result = writev(fd, buffers, vec_len);
+  bytes_written = result;
+
+  if (result < 0)
+    {
+      bytes_written = 0;
+      if (errno == EAGAIN) /* Non blocking */
+        result = 0;
+      else
+        {
+          is_error = JNI_TRUE;
+          error_msg = strerror(errno);
+        }
+    }
+  else if (result == 0) /* EOF??  Does this happen on a write */
+    result = -1;
+    
+  for (i = 0; i < vec_len; i++)
+    {
+      struct JCL_buffer buf = bi_list[i];
+
+      if (bytes_written > (buf.limit - buf.position))
+        buf.count = (buf.limit - buf.position);
+      else
+        buf.count = bytes_written;
+        
+      bytes_written -= buf.count;
+      
+      JCL_release_buffer(env, &buf, JNI_ABORT);
+    }
+
+  /* A GC, a GC, my kingdom for a GC */      
+  JCL_free(env, buffers);
+  JCL_free(env, bi_list);
+      
+  if (is_error == JNI_TRUE)
+    {
+      JCL_ThrowException(env, IO_EXCEPTION, error_msg);
+      return -1;
+    }
+    
+  return result;
+}
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
_______________________________________________
Classpath mailing list
Classpath@gnu.org
http://lists.gnu.org/mailman/listinfo/classpath

Reply via email to