Hi,

Another punt at the Non-blocking IO and Scatter/Gather stuff.  This
patch also adds scatter/gather support to the FileChannelImpl.

ChangeLog:

2006-03-19  Michael Barker <[EMAIL PROTECTED]>
        
        * vm/reference/gnu/java/nio/VMChannel.java: Added, supports setting 
        non-blocking and scatter-gather io operations.
        * gnu/java/nio/PipeImpl.java: Retrofitted to use VMChannel
        * gnu/java/nio/SelectorImpl.java
        (register) Added condition for
gnu.java.nio.SocketChannelSelectionKeyImpl
        * gnu/java/nio/SocketChannelSelectionKeyImpl.java Added.
        * gnu/java/nio/channels/FileChannelImpl.java: Retrofitted to use
VMChannel
        * java/nio/FileChannel.java
        (read (ByteBuffer)) Changed to call abstract method.
        (write (ByteBuffer)) Changed to call abstract method.
        * include/gnu_java_nio_VMChannel.h: Added.
        * native/jni/java-nio/gnu_java_nio_VMChannel.c: Added.

Regards,
Michael Barker
Index: ChangeLog
===================================================================
RCS file: /cvsroot/classpath/classpath/ChangeLog,v
retrieving revision 1.6923
diff -u -r1.6923 ChangeLog
--- ChangeLog	27 Mar 2006 20:05:15 -0000	1.6923
+++ ChangeLog	27 Mar 2006 20:15:10 -0000
@@ -1360,6 +1360,21 @@
 	* vm/reference/gnu/classpath/Unsafe.java:
 	New class to handle low-level facilities for concurrency.
 
+2006-03-19  Michael Barker <[EMAIL PROTECTED]>
+	
+	* vm/reference/gnu/java/nio/VMChannel.java: Added, supports setting 
+	non-blocking and scatter-gather io operations.
+	* gnu/java/nio/PipeImpl.java: Retrofitted to use VMChannel
+	* gnu/java/nio/SelectorImpl.java
+	(register) Added condition for gnu.java.nio.SocketChannelSelectionKeyImpl
+	* gnu/java/nio/SocketChannelSelectionKeyImpl.java Added.
+	* gnu/java/nio/channels/FileChannelImpl.java: Retrofitted to use VMChannel
+	* java/nio/FileChannel.java
+	(read (ByteBuffer)) Changed to call abstract method.
+	(write (ByteBuffer)) Changed to call abstract method.
+	* include/gnu_java_nio_VMChannel.h: Added.
+	* native/jni/java-nio/gnu_java_nio_VMChannel.c: Added.
+
 2006-03-19  Mark Wielaard  <[EMAIL PROTECTED]>
 
 	* include/Makefile.am: Rename PlainDatagramSocketImpl to
Index: gnu/java/nio/PipeImpl.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/nio/PipeImpl.java,v
retrieving revision 1.11
diff -u -r1.11 PipeImpl.java
--- gnu/java/nio/PipeImpl.java	2 Jul 2005 20:32:13 -0000	1.11
+++ gnu/java/nio/PipeImpl.java	27 Mar 2006 20:15:12 -0000
@@ -37,6 +37,7 @@
 
 package gnu.java.nio;
 
+
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.channels.Pipe;
@@ -47,12 +48,14 @@
   public static final class SourceChannelImpl extends Pipe.SourceChannel
   {
     private int native_fd;
+    private VMChannel vmch;
     
     public SourceChannelImpl (SelectorProvider selectorProvider,
                               int native_fd)
     {
       super (selectorProvider);
       this.native_fd = native_fd;
+      vmch = VMChannel.getVMChannel(this);
     }
 
     protected final void implCloseSelectableChannel()
@@ -64,19 +67,19 @@
     protected void implConfigureBlocking (boolean blocking)
       throws IOException
     {
-      throw new Error ("Not implemented");
+      vmch.setBlocking(blocking);
     }
 
     public final int read (ByteBuffer src)
       throws IOException
     {
-      throw new Error ("Not implemented");
+      return vmch.read(src);
     }
 
     public final long read (ByteBuffer[] srcs)
       throws IOException
     {
-      return read (srcs, 0, srcs.length);
+      return vmch.readScattering(srcs, 0, srcs.length);
     }
 
     public final synchronized long read (ByteBuffer[] srcs, int offset,
@@ -89,13 +92,7 @@
 	  || len > srcs.length - offset)
 	throw new IndexOutOfBoundsException();
 
-      long bytesRead = 0;
-      
-      for (int index = 0; index < len; index++)
-	bytesRead += read (srcs [offset + index]);
-
-      return bytesRead;
-
+      return vmch.readScattering(srcs, offset, len);
     }
 
     public final int getNativeFD()
@@ -107,12 +104,14 @@
   public static final class SinkChannelImpl extends Pipe.SinkChannel
   {
     private int native_fd;
+    private VMChannel vmch;
     
     public SinkChannelImpl (SelectorProvider selectorProvider,
                             int native_fd)
     {
       super (selectorProvider);
       this.native_fd = native_fd;
+      vmch = VMChannel.getVMChannel(this);
     }
 
     protected final void implCloseSelectableChannel()
@@ -124,19 +123,19 @@
     protected final void implConfigureBlocking (boolean blocking)
       throws IOException
     {
-      throw new Error ("Not implemented");
+      vmch.setBlocking(blocking);
     }
 
     public final int write (ByteBuffer dst)
       throws IOException
     {
-      throw new Error ("Not implemented");
+      return vmch.write(dst);
     }
 
     public final long write (ByteBuffer[] srcs)
       throws IOException
     {
-      return write (srcs, 0, srcs.length);
+      return vmch.writeGathering(srcs, 0, srcs.length);
     }
 
     public final synchronized long write (ByteBuffer[] srcs, int offset, int len)
@@ -147,13 +146,8 @@
 	  || len < 0
 	  || len > srcs.length - offset)
 	throw new IndexOutOfBoundsException();
-
-      long bytesWritten = 0;
       
-      for (int index = 0; index < len; index++)
-	bytesWritten += write (srcs [offset + index]);
-
-      return bytesWritten;
+      return vmch.writeGathering(srcs, offset, len);
     }
 
     public final int getNativeFD()
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	27 Mar 2006 20:15:13 -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.SocketChannelImpl)
+      result = new gnu.java.nio.SocketChannelSelectionKeyImpl((gnu.java.nio.SocketChannelImpl)ch, this);
     else
       throw new InternalError ("No known channel type");
 
Index: gnu/java/nio/SocketChannelImpl.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/nio/SocketChannelImpl.java,v
retrieving revision 1.29
diff -u -r1.29 SocketChannelImpl.java
--- gnu/java/nio/SocketChannelImpl.java	27 Dec 2005 02:27:01 -0000	1.29
+++ gnu/java/nio/SocketChannelImpl.java	27 Mar 2006 20:15:13 -0000
@@ -41,8 +41,6 @@
 import gnu.java.net.PlainSocketImpl;
 
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
 import java.net.InetSocketAddress;
 import java.net.Socket;
 import java.net.SocketAddress;
@@ -110,7 +108,8 @@
 
   protected void implConfigureBlocking (boolean blocking) throws IOException
   {
-    socket.setSoTimeout (blocking ? 0 : NIOConstants.DEFAULT_TIMEOUT);
+    VMChannel vmch = VMChannel.getVMChannel(impl);
+    vmch.setBlocking(blocking);
   }   
 
   public boolean connect (SocketAddress remote) throws IOException
@@ -215,25 +214,6 @@
   {
     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;
@@ -241,8 +221,8 @@
     try
       {
         begin();
-        socket.getPlainSocketImpl().setInChannelOperation(true);
-        readBytes = input.read (data, offset, len);
+        VMChannel vmch = VMChannel.getVMChannel(impl);
+        readBytes = vmch.read(dst);
         completed = true;
       }
     finally
@@ -251,15 +231,6 @@
         socket.getPlainSocketImpl().setInChannelOperation(false);
       }
 
-    if (readBytes > 0)
-      if (dst.hasArray())
-	{
-	  dst.position (dst.position() + readBytes);
-	}
-      else
-        {
-          dst.put (data, offset, readBytes);
-        }
 
     return readBytes;
   }
@@ -270,16 +241,22 @@
     if (!isConnected())
       throw new NotYetConnectedException();
     
-    if ((offset < 0)
-        || (offset > dsts.length)
-        || (length < 0)
-        || (length > (dsts.length - offset)))
-      throw new IndexOutOfBoundsException();
-      
     long readBytes = 0;
+    
+    boolean completed = false;
 
-    for (int index = offset; index < length; index++)
-      readBytes += read (dsts [index]);
+    try
+      {
+        begin();
+        VMChannel vmch = VMChannel.getVMChannel(impl);
+        readBytes = vmch.readScattering(dsts, offset, length);
+        completed = true;
+      }
+    finally
+      {
+        end (completed);
+        socket.getPlainSocketImpl().setInChannelOperation(false);
+      }
 
     return readBytes;
   }
@@ -289,30 +266,15 @@
   {
     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();
+    int readBytes = 0;
     boolean completed = false;
 
     try
       {
         begin();
-        socket.getPlainSocketImpl().setInChannelOperation(true);
-        output.write (data, offset, len);
+        VMChannel vmch = VMChannel.getVMChannel(impl);
+        readBytes = vmch.write(src);
         completed = true;
       }
     finally
@@ -321,12 +283,8 @@
         socket.getPlainSocketImpl().setInChannelOperation(false);
       }
 
-    if (src.hasArray())
-      {
-	src.position (src.position() + len);
-      }
-    
-    return len;
+
+    return readBytes;
   }
 
   public long write (ByteBuffer[] srcs, int offset, int length)
@@ -334,18 +292,24 @@
   {
     if (!isConnected())
       throw new NotYetConnectedException();
-    
-    if ((offset < 0)
-        || (offset > srcs.length)
-        || (length < 0)
-        || (length > (srcs.length - offset)))
-      throw new IndexOutOfBoundsException();
-      
-    long writtenBytes = 0;
 
-    for (int index = offset; index < length; index++)
-      writtenBytes += write (srcs [index]);
+    long readBytes = 0;
+    boolean completed = false;
+
+    try
+      {
+        begin();
+        VMChannel vmch = VMChannel.getVMChannel(impl);
+        readBytes = vmch.writeGathering(srcs, offset, length);
+        completed = true;
+      }
+    finally
+      {
+        end (completed);
+        socket.getPlainSocketImpl().setInChannelOperation(false);
+      }
+
 
-    return writtenBytes;
+    return readBytes;
   }
 }
Index: gnu/java/nio/channels/FileChannelImpl.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/nio/channels/FileChannelImpl.java,v
retrieving revision 1.21
diff -u -r1.21 FileChannelImpl.java
--- gnu/java/nio/channels/FileChannelImpl.java	1 Mar 2006 17:42:48 -0000	1.21
+++ gnu/java/nio/channels/FileChannelImpl.java	27 Mar 2006 20:15:14 -0000
@@ -40,6 +40,7 @@
 
 import gnu.classpath.Configuration;
 import gnu.java.nio.FileLockImpl;
+import gnu.java.nio.VMChannel;
 
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -102,6 +103,7 @@
   // 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;
 
@@ -123,6 +125,7 @@
     description = path;
     fd = open (path, mode);
     this.mode = mode;
+    this.ch = VMChannel.getVMChannel(this);
 
     // First open the file and then check if it is a a directory
     // to avoid race condition.
@@ -155,6 +158,7 @@
     this.fd = fd;
     this.mode = mode;
     this.description = "descriptor(" + fd + ")";
+    this.ch = VMChannel.getVMChannel(this);
   }
 
   private native int open (String path, int mode) throws FileNotFoundException;
@@ -181,6 +185,7 @@
 
   public int read (ByteBuffer dst) throws IOException
   {
+    /*
     int result;
     byte[] buffer = new byte [dst.remaining ()];
     
@@ -190,6 +195,8 @@
       dst.put (buffer, 0, result);
 
     return result;
+    */
+    return ch.read(dst);
   }
 
   public int read (ByteBuffer dst, long position)
@@ -214,33 +221,12 @@
   public long read (ByteBuffer[] dsts, int offset, int length)
     throws IOException
   {
-    long result = 0;
-
-    for (int i = offset; i < offset + length; i++)
-      {
-        result += read (dsts [i]);
-      }
-
-    return result;
+    return ch.readScattering(dsts, offset, length);
   }
 
   public int write (ByteBuffer src) throws IOException
   {
-    int len = src.remaining ();
-    if (src.hasArray())
-      {
-	byte[] buffer = src.array();
-	write(buffer, src.arrayOffset() + src.position(), len);
-	src.position(src.position() + len);
-      }
-    else
-      {
-	// Use a more efficient native method! FIXME!
-	byte[] buffer = new byte [len];
-    	src.get (buffer, 0, len);
-	write (buffer, 0, len);
-      }
-    return len;
+    return ch.write(src);
   }
     
   public int write (ByteBuffer src, long position)
@@ -274,14 +260,7 @@
   public long write(ByteBuffer[] srcs, int offset, int length)
     throws IOException
   {
-    long result = 0;
-
-    for (int i = offset;i < offset + length;i++)
-      {
-        result += write (srcs[i]);
-      }
-    
-    return result;
+    return ch.writeGathering(srcs, offset, length);
   }
 				   
   public native MappedByteBuffer mapImpl (char mode, long position, int size)
@@ -563,4 +542,12 @@
 	    + ",mode=" + mode + ","
 	    + description + "]");
   }
+
+  /**
+   * @return The native file descriptor.
+   */
+  public int getNativeFD()
+  {
+    return fd;
+  }
 }
Index: include/Makefile.am
===================================================================
RCS file: /cvsroot/classpath/classpath/include/Makefile.am,v
retrieving revision 1.55
diff -u -r1.55 Makefile.am
--- include/Makefile.am	19 Mar 2006 23:17:16 -0000	1.55
+++ include/Makefile.am	27 Mar 2006 20:15:17 -0000
@@ -117,6 +117,7 @@
 $(XMLJ_H_FILES) \
 $(GTKPEER_H_FILES) \
 $(QTPEER_H_FILES) \
+$(top_srcdir)/include/gnu_java_nio_VMChannel.h \
 $(top_srcdir)/include/gnu_java_net_VMPlainDatagramSocketImpl.h \
 $(top_srcdir)/include/gnu_java_net_VMPlainSocketImpl.h \
 $(top_srcdir)/include/gnu_java_nio_VMPipe.h \
@@ -164,6 +165,8 @@
 $(top_srcdir)/include/gnu_javax_sound_midi_dssi_%.h: $(top_builddir)/$(CLASSDIR)/gnu/javax/sound/midi/dssi/%.class
 	$(JAVAH) -o $@ gnu.javax.sound.midi.dssi.$*
 
+$(top_srcdir)/include/gnu_java_nio_VMChannel.h: $(top_srcdir)/vm/reference/gnu/java/nio/VMChannel.java
+	$(JAVAH) -o $@ gnu.java.nio.VMChannel
 $(top_srcdir)/include/gnu_java_net_VMPlainDatagramSocketImpl.h: $(top_srcdir)/vm/reference/gnu/java/net/VMPlainDatagramSocketImpl.java
 	$(JAVAH) -o $@ gnu.java.net.VMPlainDatagramSocketImpl
 $(top_srcdir)/include/gnu_java_net_VMPlainSocketImpl.h: $(top_srcdir)/vm/reference/gnu/java/net/VMPlainSocketImpl.java
Index: java/nio/channels/FileChannel.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/nio/channels/FileChannel.java,v
retrieving revision 1.15
diff -u -r1.15 FileChannel.java
--- java/nio/channels/FileChannel.java	1 Mar 2006 17:42:48 -0000	1.15
+++ java/nio/channels/FileChannel.java	27 Mar 2006 20:15:19 -0000
@@ -114,12 +114,7 @@
    */
   public final long write(ByteBuffer[] srcs) throws IOException
   {
-    long result = 0;
-
-    for (int i = 0; i < srcs.length; i++)
-      result += write(srcs[i]);
-
-    return result;
+    return write(srcs, 0, srcs.length);
   }
 
   /**
@@ -169,12 +164,7 @@
    */
   public final long read(ByteBuffer[] dsts) throws IOException
   {
-    long result = 0;
-
-    for (int i = 0; i < dsts.length; i++)
-      read(dsts[i]);
-
-    return result;
+    return read(dsts, 0, dsts.length);
   }
 
   /**
Index: native/jni/java-nio/Makefile.am
===================================================================
RCS file: /cvsroot/classpath/classpath/native/jni/java-nio/Makefile.am,v
retrieving revision 1.22
diff -u -r1.22 Makefile.am
--- native/jni/java-nio/Makefile.am	10 Mar 2006 01:36:10 -0000	1.22
+++ native/jni/java-nio/Makefile.am	27 Mar 2006 20:15:24 -0000
@@ -1,6 +1,7 @@
 nativeexeclib_LTLIBRARIES = libjavanio.la
 
 libjavanio_la_SOURCES = gnu_java_nio_VMPipe.c \
+			gnu_java_nio_VMChannel.c \
 			gnu_java_nio_VMSelector.c \
 			gnu_java_nio_channels_FileChannelImpl.c \
 			gnu_java_nio_charset_iconv_IconvDecoder.c \
Index: gnu/java/nio/SocketChannelSelectionKeyImpl.java
===================================================================
RCS file: gnu/java/nio/SocketChannelSelectionKeyImpl.java
diff -N gnu/java/nio/SocketChannelSelectionKeyImpl.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gnu/java/nio/SocketChannelSelectionKeyImpl.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,69 @@
+/* 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;
+
+
+/**
+ * @author Michael Barker <[EMAIL PROTECTED]>
+ *
+ */
+public class SocketChannelSelectionKeyImpl extends SelectionKeyImpl
+{
+
+  SocketChannelImpl ch;
+  
+  /**
+   * @param ch
+   * @param impl
+   */
+  public SocketChannelSelectionKeyImpl(SocketChannelImpl ch, SelectorImpl impl)
+  {
+    super(ch, impl);
+    this.ch = (SocketChannelImpl) ch;
+  }
+
+  /**
+   * Returns the native file/socket descriptor as an int.
+   */
+  public int getNativeFD()
+  {
+    return ch.getPlainSocketImpl().getNativeFD();
+  }
+
+}
Index: include/gnu_java_nio_VMChannel.h
===================================================================
RCS file: include/gnu_java_nio_VMChannel.h
diff -N include/gnu_java_nio_VMChannel.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ include/gnu_java_nio_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_VMChannel__
+#define __gnu_java_nio_VMChannel__
+
+#include <jni.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+JNIEXPORT void JNICALL Java_gnu_java_nio_VMChannel_setBlocking (JNIEnv *env, jobject, jint, jboolean);
+JNIEXPORT jint JNICALL Java_gnu_java_nio_VMChannel_read (JNIEnv *env, jobject, jint, jobject);
+JNIEXPORT jlong JNICALL Java_gnu_java_nio_VMChannel_readScattering (JNIEnv *env, jobject, jint, jobjectArray, jint, jint);
+JNIEXPORT jint JNICALL Java_gnu_java_nio_VMChannel_write (JNIEnv *env, jobject, jint, jobject);
+JNIEXPORT jlong JNICALL Java_gnu_java_nio_VMChannel_writeGathering (JNIEnv *env, jobject, jint, jobjectArray, jint, jint);
+JNIEXPORT void JNICALL Java_gnu_java_nio_VMChannel_initIDs (JNIEnv *env, jclass);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gnu_java_nio_VMChannel__ */
Index: native/jni/java-nio/gnu_java_nio_VMChannel.c
===================================================================
RCS file: native/jni/java-nio/gnu_java_nio_VMChannel.c
diff -N native/jni/java-nio/gnu_java_nio_VMChannel.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ native/jni/java-nio/gnu_java_nio_VMChannel.c	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,519 @@
+/* gnu_java_nio_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_VMChannel.h"
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif /* HAVE_FCNTL_H */
+
+#define IO_EXCEPTION "java/io/IOException"
+#define NON_READABLE_CHANNEL_EXCEPTION "java/nio/channels/NonReadableChannelException"
+#define NON_WRITABLE_CHANNEL_EXCEPTION "java/nio/channels/NonWritableChannelException"
+
+/*
+ * Limit to maximum of 16 buffers
+ */
+#define JCL_IOV_MAX 16
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+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;
+
+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;
+  jint offset;
+  jint position;
+  jint limit;
+  jint count;
+};
+
+void
+JCL_print_buffer(JNIEnv *env, struct JCL_buffer *buf)
+{
+  fprintf(stdout, "Buffer - type: %d, ptr: %d\n", buf->type, (int)buf->ptr);
+  fflush(stdout);
+}
+
+
+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->offset = 0;
+  buf->count = 0;
+  buf->type = UNKNOWN;
+    
+  if (address != NULL)
+    {
+      buf->ptr = (jbyte *) JCL_GetRawData(env, address);
+      buf->type = DIRECT;
+      (*env)->DeleteLocalRef(env, address);
+    }
+  else
+    {
+      jboolean has_array;
+      has_array = (*env)->CallBooleanMethod(env, bbuf, has_array_mid);
+      
+      if (has_array == JNI_TRUE)
+        {
+          jbyteArray arr;
+          buf->offset = (*env)->CallIntMethod(env, bbuf, array_offset_mid);
+          arr = (*env)->CallObjectMethod(env, bbuf, array_mid);
+          buf->ptr = (*env)->GetByteArrayElements(env, arr, 0);
+          buf->type = ARRAY;
+          (*env)->DeleteLocalRef(env, arr);
+        }
+      else
+        {
+          return -1;
+        }
+    }
+      
+  return 0;
+}
+
+void
+JCL_release_buffer(JNIEnv *env, struct JCL_buffer *buf, jobject bbuf, 
+    jint action)
+{
+  jbyteArray arr;
+  
+  /* Set the position to the appropriate value */
+  if (buf->count > 0)
+    {
+      jobject bbufTemp;
+      bbufTemp = (*env)->CallObjectMethod(env, bbuf, set_position_mid, 
+                                          buf->position + buf->count);
+      (*env)->DeleteLocalRef(env, bbufTemp);
+    }
+    
+  switch (buf->type)
+    {
+    case DIRECT:
+      break;
+    case ARRAY:
+      arr = (*env)->CallObjectMethod(env, bbuf, array_mid);
+      (*env)->ReleaseByteArrayElements(env, arr, buf->ptr, action);
+      (*env)->DeleteLocalRef(env, arr);
+      break;
+    case UNKNOWN:
+      /* TODO: Handle buffers that are not direct or array backed */
+      break;
+    }
+}
+
+void
+JCL_cleanup_buffers(JNIEnv *env, 
+                    struct JCL_buffer *bi_list, 
+                    jint vec_len, 
+                    jobjectArray bbufs, 
+                    jint offset,
+                    jlong num_bytes)
+{
+  jint i;
+  
+  /* Update all of the bbufs with the approriate information */
+  for (i = 0; i < vec_len; i++)
+    {
+      struct JCL_buffer* buf;
+      jobject bbuf;
+      
+      buf = &bi_list[i];
+      bbuf = (*env)->GetObjectArrayElement(env, bbufs, offset + i);
+
+      if (num_bytes > (buf->limit - buf->position))
+        buf->count = (buf->limit - buf->position);
+      else
+        buf->count = num_bytes;
+        
+      num_bytes -= buf->count;
+      
+      JCL_release_buffer(env, buf, bbuf, JNI_ABORT);
+      (*env)->DeleteLocalRef(env, bbuf);
+    }
+}
+
+
+JNIEXPORT void JNICALL 
+Java_gnu_java_nio_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");
+}
+
+JNIEXPORT void JNICALL 
+Java_gnu_java_nio_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_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 if (errno == EBADF) /* Bad fd */
+        {
+          JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
+          JCL_ThrowException (env, NON_READABLE_CHANNEL_EXCEPTION, 
+                              strerror(errno));
+          return -1;
+        }            
+      else
+        {
+          JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
+      	  JCL_ThrowException (env, IO_EXCEPTION, strerror(errno));
+      	  return -1;
+        }
+    }
+  else 
+    
+  JCL_release_buffer(env, &buf, bbuf, JNI_COMMIT);
+  
+  return result;
+}
+
+JNIEXPORT jint JNICALL 
+Java_gnu_java_nio_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.position + buf.offset]), len);
+  buf.count = result;
+  
+  if (result == -1)
+    {
+      if (errno == EAGAIN) /* Non-blocking */
+          result = 0;
+      else
+        {
+          JCL_release_buffer(env, &buf, bbuf, JNI_ABORT);
+          JCL_ThrowException(env, IO_EXCEPTION, strerror(errno));
+          return -1;
+        }
+    }
+    
+  JCL_release_buffer(env, &buf, bbuf, 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 16 buffers.  This is for 
+ * compatibiliy with Sun.
+ */
+JNIEXPORT jlong JNICALL 
+Java_gnu_java_nio_VMChannel_readScattering (JNIEnv *env, 
+	jobject o __attribute__ ((__unused__)), 
+	jint fd, 
+	jobjectArray bbufs, 
+	jint offset, 
+	jint length)
+{
+  jint i;
+  jboolean is_error = JNI_FALSE;
+  char *error_msg;
+  struct iovec buffers[JCL_IOV_MAX];
+  struct JCL_buffer bi_list[JCL_IOV_MAX];
+  ssize_t result;
+  jint vec_len = length < JCL_IOV_MAX ? length : JCL_IOV_MAX;
+  jlong bytes_read = 0;      
+  
+  /* Build the vector of buffers to read into */
+  for (i = 0; i < vec_len; i++)
+    {
+      struct JCL_buffer* buf;
+      jobject bbuf;
+      
+      buf = &bi_list[i];
+      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;
+      (*env)->DeleteLocalRef(env, bbuf);
+    }
+    
+  /* Work the scattering magic */
+  result = readv(fd, buffers, vec_len);
+  bytes_read = (jlong) result;
+  
+  /* Handle the response */
+  if (result < 0)
+    {
+      if (errno == EAGAIN) /* Non blocking */
+        result = 0;
+      else if (errno == EBADF) /* Bad fd */
+        {
+          JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_read);
+          JCL_ThrowException (env, NON_READABLE_CHANNEL_EXCEPTION, 
+                              strerror(errno));
+          return -1;
+        } 
+      else
+        {
+          JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_read);
+          JCL_ThrowException (env, IO_EXCEPTION, strerror(errno));
+          return -1;
+        }
+      bytes_read = 0;
+    }
+  else if (result == 0) /* EOF */
+    {
+      result = -1;
+    }
+    
+  JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_read);
+                  
+  return (jlong) 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 16 buffers.  This is for 
+ * compatibiliy with Sun.
+ */
+JNIEXPORT jlong JNICALL 
+Java_gnu_java_nio_VMChannel_writeGathering (JNIEnv *env, 
+	jobject o __attribute__ ((__unused__)), 
+	jint fd, 
+	jobjectArray bbufs, 
+	jint offset, 
+	jint length)
+{
+  int i;
+  jboolean is_error = JNI_FALSE;
+  char *error_msg;
+  struct iovec buffers[JCL_IOV_MAX];
+  struct JCL_buffer bi_list[JCL_IOV_MAX];
+  ssize_t result;
+  jint vec_len = length < JCL_IOV_MAX ? length : JCL_IOV_MAX;
+  jlong bytes_written;
+  
+  
+  /* Build the vector of buffers to read into */
+  for (i = 0; i < vec_len; i++)
+    {
+      struct JCL_buffer* buf;
+      jobject bbuf;
+      
+      buf = &bi_list[i];
+      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;
+      (*env)->DeleteLocalRef(env, bbuf);
+    }
+    
+  /* Work the gathering magic */
+  result = writev(fd, buffers, vec_len);
+  bytes_written = (jlong) result;
+
+  if (result < 0)
+    {
+      bytes_written = 0;
+      if (errno == EAGAIN) /* Non blocking */
+        result = 0;
+      else if (errno == EBADF) /* Bad fd */
+        {
+          JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, 
+                              bytes_written);
+          JCL_ThrowException (env, NON_WRITABLE_CHANNEL_EXCEPTION, 
+                              strerror(errno));
+          return -1;
+        } 
+      else
+        {
+          JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset,
+                              bytes_written);
+          JCL_ThrowException (env, IO_EXCEPTION, strerror(errno));
+          return -1;
+        }
+    }
+  else if (result == 0) /* EOF??  Does this happen on a write */
+    result = -1;
+    
+  JCL_cleanup_buffers(env, bi_list, vec_len, bbufs, offset, bytes_written);    
+  return (jlong) result;
+}
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
Index: vm/reference/gnu/java/nio/VMChannel.java
===================================================================
RCS file: vm/reference/gnu/java/nio/VMChannel.java
diff -N vm/reference/gnu/java/nio/VMChannel.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ vm/reference/gnu/java/nio/VMChannel.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,197 @@
+/* VMChannel.java -- Native interface suppling channel operations.
+   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 gnu.java.net.PlainSocketImpl;
+import gnu.java.nio.PipeImpl.SinkChannelImpl;
+import gnu.java.nio.PipeImpl.SourceChannelImpl;
+import gnu.java.nio.channels.FileChannelImpl;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * Native interface to support configuring of channel to run in a non-blocking
+ * manner and support scatter/gather io operations.
+ * 
+ * @author Michael Barker <[EMAIL PROTECTED]>
+ *
+ */
+public class VMChannel
+{
+  private final int fd;
+  
+  private VMChannel(int fd)
+  {
+    this.fd = fd;
+  }
+  
+  public static VMChannel getVMChannel(PlainSocketImpl socket)
+  {
+    return new VMChannel(socket.getNativeFD());
+  }
+  
+  public static VMChannel getVMChannel(SourceChannelImpl source)
+  {
+    return new VMChannel(source.getNativeFD());
+  }
+  
+  public static VMChannel getVMChannel(SinkChannelImpl sink)
+  {
+    return new VMChannel(sink.getNativeFD());
+  }
+  
+  public static VMChannel getVMChannel(FileChannelImpl file)
+  {
+    return new VMChannel(file.getNativeFD());
+  }
+
+  static
+  {
+    // load the shared library needed for native methods.
+    if (Configuration.INIT_LOAD_LIBRARY)
+      {
+        System.loadLibrary ("javanio");
+      }
+    initIDs();
+  }
+  
+  /**
+   * Set the file descriptor to have the required blocking
+   * setting.
+   * 
+   * @param fd
+   * @param blocking
+   */
+  public native void setBlocking(int fd, boolean blocking);
+  
+  public void setBlocking(boolean blocking)
+  {
+    setBlocking(fd, 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;
+  
+  public int read(ByteBuffer dst)
+    throws IOException
+  {
+    return read(fd, dst);
+  }
+  
+  /**
+   * 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;
+
+  public long readScattering(ByteBuffer[] dsts, int offset, int length)
+    throws IOException
+  {
+    if (offset + length > dsts.length)
+      throw new IndexOutOfBoundsException("offset + length > dsts.length");
+    
+    return readScattering(fd, dsts, offset, length);
+  }
+  
+  /**
+   * 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;
+
+  public int write(ByteBuffer src)
+    throws IOException
+  {
+    return write(fd, src);
+  }
+  
+  /**
+   * 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;
+  
+  public long writeGathering(ByteBuffer[] srcs, int offset, int length)
+    throws IOException
+  {
+    if (offset + length > srcs.length)
+      throw new IndexOutOfBoundsException("offset + length > srcs.length");
+    
+    return writeGathering(fd, srcs, offset, length);
+  }
+  
+  private native static void initIDs();
+
+}

Reply via email to