summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCasey Marshall <csm@gnu.org>2006-05-31 00:57:16 +0000
committerCasey Marshall <csm@gnu.org>2006-05-31 00:57:16 +0000
commite0556b51c4223843c801b3cc6a10c13248cff8fd (patch)
tree74511c1caaaad85ef11ab9b524091c0d5d86a9f2
parent92cf25ad0d925e4d753577f3a70359a77e86cea5 (diff)
downloadclasspath-jessie-nio.tar.gz
2006-05-30 Casey Marshall <csm@gnu.org>jessie-nio
Merge scatter/gather NIO patch by Michael Barker to branch.
-rw-r--r--ChangeLog-jessie-nio4
-rw-r--r--gnu/java/nio/PipeImpl.java32
-rw-r--r--gnu/java/nio/SelectorImpl.java2
-rw-r--r--gnu/java/nio/SocketChannelImpl.java120
-rw-r--r--gnu/java/nio/channels/FileChannelImpl.java49
-rw-r--r--include/Makefile.am3
-rw-r--r--java/nio/channels/FileChannel.java14
-rw-r--r--native/jni/java-nio/Makefile.am1
-rw-r--r--native/jni/java-nio/gnu_java_nio_VMChannel.c519
-rw-r--r--vm/reference/gnu/java/nio/VMChannel.java197
10 files changed, 801 insertions, 140 deletions
diff --git a/ChangeLog-jessie-nio b/ChangeLog-jessie-nio
index 82dc3c7f9..a325c4f1b 100644
--- a/ChangeLog-jessie-nio
+++ b/ChangeLog-jessie-nio
@@ -1,3 +1,7 @@
+2006-05-30 Casey Marshall <csm@gnu.org>
+
+ Merge scatter/gather NIO patch by Michael Barker to branch.
+
2006-03-28 Casey Marshall <csm@gnu.org>
* jessie-tests/run-tests.sh: add new tests; count number of tests
diff --git a/gnu/java/nio/PipeImpl.java b/gnu/java/nio/PipeImpl.java
index f7b01c8b7..cccaa3988 100644
--- a/gnu/java/nio/PipeImpl.java
+++ b/gnu/java/nio/PipeImpl.java
@@ -37,6 +37,7 @@ exception statement from your version. */
package gnu.java.nio;
+
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.Pipe;
@@ -47,12 +48,14 @@ class PipeImpl extends Pipe
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 @@ class PipeImpl extends Pipe
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 @@ class PipeImpl extends Pipe
|| 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 @@ class PipeImpl extends Pipe
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 @@ class PipeImpl extends Pipe
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 @@ class PipeImpl extends Pipe
|| 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()
diff --git a/gnu/java/nio/SelectorImpl.java b/gnu/java/nio/SelectorImpl.java
index e10f71574..7639c9ae3 100644
--- a/gnu/java/nio/SelectorImpl.java
+++ b/gnu/java/nio/SelectorImpl.java
@@ -379,6 +379,8 @@ public class SelectorImpl extends AbstractSelector
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");
diff --git a/gnu/java/nio/SocketChannelImpl.java b/gnu/java/nio/SocketChannelImpl.java
index 680eba2f9..697987eb6 100644
--- a/gnu/java/nio/SocketChannelImpl.java
+++ b/gnu/java/nio/SocketChannelImpl.java
@@ -41,8 +41,6 @@ package gnu.java.nio;
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 @@ public final class SocketChannelImpl extends SocketChannel
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 @@ 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;
@@ -241,8 +221,8 @@ public final class SocketChannelImpl extends SocketChannel
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 @@ public final class SocketChannelImpl extends SocketChannel
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 @@ public final class SocketChannelImpl extends SocketChannel
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 @@ public final class SocketChannelImpl extends SocketChannel
{
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 @@ public final class SocketChannelImpl extends SocketChannel
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 @@ public final class SocketChannelImpl extends SocketChannel
{
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]);
-
- return writtenBytes;
+
+ 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 readBytes;
}
}
diff --git a/gnu/java/nio/channels/FileChannelImpl.java b/gnu/java/nio/channels/FileChannelImpl.java
index 671ae5bb1..ed439e141 100644
--- a/gnu/java/nio/channels/FileChannelImpl.java
+++ b/gnu/java/nio/channels/FileChannelImpl.java
@@ -40,6 +40,7 @@ package gnu.java.nio.channels;
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 @@ public final class FileChannelImpl extends FileChannel
// 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 @@ public final class FileChannelImpl extends FileChannel
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 @@ public final class FileChannelImpl extends FileChannel
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 final class FileChannelImpl extends FileChannel
public int read (ByteBuffer dst) throws IOException
{
+ /*
int result;
byte[] buffer = new byte [dst.remaining ()];
@@ -190,6 +195,8 @@ public final class FileChannelImpl extends FileChannel
dst.put (buffer, 0, result);
return result;
+ */
+ return ch.read(dst);
}
public int read (ByteBuffer dst, long position)
@@ -214,33 +221,12 @@ public final class FileChannelImpl extends FileChannel
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 final class FileChannelImpl extends FileChannel
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 @@ public final class FileChannelImpl extends FileChannel
+ ",mode=" + mode + ","
+ description + "]");
}
+
+ /**
+ * @return The native file descriptor.
+ */
+ public int getNativeFD()
+ {
+ return fd;
+ }
}
diff --git a/include/Makefile.am b/include/Makefile.am
index 0517e125a..160a5069a 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -119,6 +119,7 @@ $(GTKPEER_H_FILES) \
$(QTPEER_H_FILES) \
$(top_srcdir)/include/gnu_java_net_PlainDatagramSocketImpl.h \
$(top_srcdir)/include/gnu_java_net_PlainSocketImpl.h \
+$(top_srcdir)/include/gnu_java_nio_VMChannel.h \
$(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 \
@@ -168,6 +169,8 @@ $(top_srcdir)/include/gnu_java_net_PlainDatagramSocketImpl.h: $(top_srcdir)/gnu/
$(JAVAH) -o $@ gnu.java.net.PlainDatagramSocketImpl
$(top_srcdir)/include/gnu_java_net_PlainSocketImpl.h: $(top_srcdir)/gnu/java/net/PlainSocketImpl.java
$(JAVAH) -o $@ gnu.java.net.PlainSocketImpl
+$(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_nio_VMPipe.h: $(top_srcdir)/vm/reference/gnu/java/nio/VMPipe.java
$(JAVAH) -o $@ gnu.java.nio.VMPipe
$(top_srcdir)/include/gnu_java_nio_VMSelector.h: $(top_srcdir)/vm/reference/gnu/java/nio/VMSelector.java
diff --git a/java/nio/channels/FileChannel.java b/java/nio/channels/FileChannel.java
index 0eefffbe9..3aa199909 100644
--- a/java/nio/channels/FileChannel.java
+++ b/java/nio/channels/FileChannel.java
@@ -114,12 +114,7 @@ public abstract class FileChannel extends AbstractInterruptibleChannel
*/
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 abstract class FileChannel extends AbstractInterruptibleChannel
*/
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);
}
/**
diff --git a/native/jni/java-nio/Makefile.am b/native/jni/java-nio/Makefile.am
index 8fd5ba3ae..ea9562389 100644
--- a/native/jni/java-nio/Makefile.am
+++ b/native/jni/java-nio/Makefile.am
@@ -1,6 +1,7 @@
nativelib_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 \
diff --git a/native/jni/java-nio/gnu_java_nio_VMChannel.c b/native/jni/java-nio/gnu_java_nio_VMChannel.c
new file mode 100644
index 000000000..b2551e55e
--- /dev/null
+++ b/native/jni/java-nio/gnu_java_nio_VMChannel.c
@@ -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
diff --git a/vm/reference/gnu/java/nio/VMChannel.java b/vm/reference/gnu/java/nio/VMChannel.java
new file mode 100644
index 000000000..fdea8ff62
--- /dev/null
+++ b/vm/reference/gnu/java/nio/VMChannel.java
@@ -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 <mike@middlesoft.co.uk>
+ *
+ */
+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();
+
+}