[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[cp-patches] RFC: JNI implementation of Selector #1
From: |
Robert Schuster |
Subject: |
[cp-patches] RFC: JNI implementation of Selector #1 |
Date: |
Thu, 17 Mar 2005 06:49:50 +0100 |
User-agent: |
Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.5) Gecko/20050107 |
Brings Sourceforge's current no2 most-often downloaded p2p app to life.
Well, this code is a straight adaption of GCJ's CNI equivalent. However
two bug reports have been created out of this.
Please review the patch and besides normal critique answer me the
following questions:
1) Should we introduce a HAVE_SELECT switch as GCJ has?
(If yes I need help with this.)
2) strerror() is not thread-safe. Should I prefer strerror_r() which is
less portable?
The changelog entry:
2005-03-17 Robert Schuster <address@hidden>
* native/jni/java-nio/gnu_java_nio_VMSelector.c: Implemented
Java_gnu_java_nio_VMSelector_select.
cu
Robert
Index: native/jni/java-nio/gnu_java_nio_VMSelector.c
===================================================================
RCS file:
/cvsroot/classpath/classpath/native/jni/java-nio/gnu_java_nio_VMSelector.c,v
retrieving revision 1.2
diff -u -r1.2 gnu_java_nio_VMSelector.c
--- native/jni/java-nio/gnu_java_nio_VMSelector.c 26 Oct 2004 20:26:03
-0000 1.2
+++ native/jni/java-nio/gnu_java_nio_VMSelector.c 17 Mar 2005 05:37:26
-0000
@@ -1,5 +1,5 @@
/* gnu_java_nio_VMSelector.c - Native methods for SelectorImpl class
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -35,29 +35,237 @@
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
+#include <sys/select.h>
+#include <sys/time.h>
+
+#include <string.h>
+
#include <config.h>
#include <errno.h>
#include <jni.h>
#include <jcl.h>
+#include <stdio.h>
+
#include "gnu_java_nio_VMSelector.h"
-#define IO_EXCEPTION "java/io/IOException"
+void
+helper_put_filedescriptors(JNIEnv *, jintArray, fd_set *, int *);
+
+void
+helper_get_filedescriptors (JNIEnv *, jintArray*, fd_set *);
+
+void
+helper_reset (JNIEnv *, jintArray*);
+
+int
+helper_select (JNIEnv *, jclass, jmethodID,
+ int, fd_set *, fd_set *, fd_set *,
+ struct timeval *);
+
+void
+helper_put_filedescriptors(JNIEnv *env, jintArray fdArray, fd_set *fds, int
*max_fd)
+{
+ jint *tmpFDArray = (*env)->GetIntArrayElements(env, fdArray, 0);
+ int size = (*env)->GetArrayLength(env, fdArray);
+ int index, fd;
+
+ for( index = 0; index < size; index++)
+ {
+ fd = tmpFDArray [index];
+
+ if (fd > 0)
+ {
+ FD_SET (tmpFDArray [index], fds);
+
+ if (tmpFDArray [index] > (*max_fd))
+ (*max_fd) = tmpFDArray [index];
+ }
+ }
+}
+
+void
+helper_get_filedescriptors (JNIEnv *env, jintArray* fdArray, fd_set *fds)
+{
+ jint *tmpFDArray = (*env)->GetIntArrayElements(env, fdArray, 0);
+ int size = (*env)->GetArrayLength(env, fdArray);
+ int index, fd;
+
+ for (index = 0; index < size; index++)
+ {
+ fd = tmpFDArray [index];
+ if (fd < 0 || !FD_ISSET (fd, fds))
+ tmpFDArray [index] = 0;
+ }
+}
+
+void
+helper_reset (JNIEnv *env, jintArray* fdArray)
+{
+ jint* tmpFDArray = (*env)->GetIntArrayElements(env, fdArray, 0);
+ int size = (*env)->GetArrayLength(env, fdArray);
+ int index;
+
+ for (index = 0; index < size; index++)
+ tmpFDArray [index] = 0;
+}
+
+/* A wrapper for select() which ignores EINTR.
+ * Taken from gclib's posix.cc
+ */
+int
+helper_select (JNIEnv *env, jclass thread_class, jmethodID thread_interrupted,
+ int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+ struct timeval *timeout)
+{
+/* FIXME: Should we support this, too? Or better fail?
+#ifdef HAVE_SELECT */
+ /* If we have a timeout, compute the absolute ending time. */
+ struct timeval end, delay, after;
+ int r;
+
+ if (timeout)
+ {
+ gettimeofday (&end, NULL);
+
+ end.tv_usec += timeout->tv_usec;
+
+ if (end.tv_usec >= 1000000)
+ {
+ ++end.tv_sec;
+ end.tv_usec -= 1000000;
+ }
+
+ end.tv_sec += timeout->tv_sec;
+ delay = *timeout;
+ }
+ else
+ {
+ /* Placate compiler. */
+ delay.tv_sec = delay.tv_usec = 0;
+ }
+
+ while (1)
+ {
+ r = select (n, readfds, writefds, exceptfds,
+ timeout ? &delay : NULL);
+
+ if (r != -1 || errno != EINTR)
+ return r;
+
+ /* Here we know we got EINTR. */
+ if ( (*env)->CallStaticBooleanMethod(env, thread_class,
thread_interrupted) ) {
+ return EINTR;
+ }
+
+ if (timeout)
+ {
+ gettimeofday (&after, NULL);
+
+ /* Now compute new timeout argument. */
+ delay.tv_usec = end.tv_usec - after.tv_usec;
+ delay.tv_sec = end.tv_sec - after.tv_sec;
+
+ if (delay.tv_usec < 0)
+ {
+ --delay.tv_sec;
+ delay.tv_usec += 1000000;
+ }
+
+ if (delay.tv_sec < 0)
+ {
+ /* We assume that the user wants a valid
select() call
+ * more than precise timing. So if we get a
series of
+ * EINTR we just keep trying with delay 0 until
we get a
+ * valid result.
+ */
+ delay.tv_sec = 0;
+ }
+ }
+ }
+/*
+#else HAVE_SELECT
+ return 0;
+#endif
+*/
+}
JNIEXPORT jint JNICALL
Java_gnu_java_nio_VMSelector_select (JNIEnv *env,
jclass obj __attribute__ ((__unused__)),
- jintArray read
- __attribute__ ((__unused__)),
- jintArray write
- __attribute__ ((__unused__)),
- jintArray except
- __attribute__ ((__unused__)),
- jlong timeout
- __attribute__ ((__unused__)))
+ jintArray read,
+ jintArray write,
+ jintArray except,
+ jlong timeout)
{
- JCL_ThrowException (env, IO_EXCEPTION, "gnu.java.nio.VMSelector.select():
not implemented");
- return 0;
+ jint result;
+ jclass thread_class = (*env)->FindClass(env, "java/lang/Thread");
+ jmethodID thread_current_thread = (*env)->GetStaticMethodID(env,
thread_class, "currentThread", "()Ljava/lang/Thread;");
+ jmethodID thread_interrupt = (*env)->GetMethodID(env, thread_class,
"interrupt", "()V");
+ jmethodID thread_interrupted = (*env)->GetMethodID(env, thread_class,
"interrupted", "()Z");
+ jobject current_thread;
+ int max_fd = 0;
+ fd_set read_fds;
+ fd_set write_fds;
+ fd_set except_fds;
+ struct timeval real_time_data;
+ struct timeval *time_data = NULL;
+
+ /* If a legal timeout value isn't given, use NULL.
+ * This means an infinite timeout. The specification
+ * also says that a zero timeout should be treated
+ * as infinite. Otherwise (if the timeout value is legal),
+ * fill our timeval struct and use it for the select.
+ */
+ if (timeout > 0)
+ {
+ real_time_data.tv_sec = timeout / 1000;
+ real_time_data.tv_usec = (timeout % 1000) * 1000;
+ time_data = &real_time_data;
+ }
+
+ /* Reset all fd_set structures */
+ FD_ZERO (&read_fds);
+ FD_ZERO (&write_fds);
+ FD_ZERO (&except_fds);
+
+ /* Fill the fd_set data structures for the _Jv_select() call. */
+ helper_put_filedescriptors (env, read, &read_fds, &max_fd);
+ helper_put_filedescriptors (env, write, &write_fds, &max_fd);
+ helper_put_filedescriptors (env, except, &except_fds, &max_fd);
+
+ /* Actually do the select */
+ result = helper_select (env, thread_class, thread_interrupted, max_fd +
1, &read_fds, &write_fds,
+ &except_fds,
time_data);
+
+ if( result == EINTR ) {
+ /* The behavior of JRE 1.4.1 is that no exception is thrown
+ * when the thread is interrupted, but the thread's interrupt
+ * status is set. Clear all of our select sets and return 0,
+ * indicating that nothing was selected.
+ */
+ current_thread = (*env)->CallStaticObjectMethod(env,
thread_class, thread_current_thread);
+ (*env)->CallVoidMethod(env, current_thread, thread_interrupt);
+
+ helper_reset (env, read);
+ helper_reset (env, write);
+ helper_reset (env, except);
+
+ return 0;
+ }
+
+ if (result < 0)
+ {
+ JCL_ThrowException (env, "java/io/IOException", strerror (errno));
+ return 0;
+ }
+
+ /* Set the file descriptors according to the values returned from
select(). */
+ helper_get_filedescriptors (env, read, &read_fds);
+ helper_get_filedescriptors (env, write, &write_fds);
+ helper_get_filedescriptors (env, except, &except_fds);
+
+ return result;
}
- [cp-patches] RFC: JNI implementation of Selector #1,
Robert Schuster <=