IntelliJ IDEA "Bad file descriptor" [SOLVED]

Sheldon Hearn sheldonh at FreeBSD.org
Mon Jul 21 03:38:22 PDT 2003


Hi folks,

The IntelliJ IDEA IDE for Java has exposed a bug in FreeBSD's native
jdk-1.4.1 (ports/java/jdk14).

Some excellent support (the norm) from Serge Baranov at IntelliJ got
us on the right track, and it wasn't long before Greg Lewis and Alexey
Zelkin isolated the problem.

The problem exists in the NIO FileChannelImpl implementation on
FreeBSD's native jdk-1.4.1.

We used Solaris' FileChannelImpl.c as a starting point for our own.  The
implementation uses the sendfile() system call.

Unfortunately sendfile() is a non-standard system call.  Solaris and
Linux implement file-to-file copy support in sendfile(), while HP-UX and
FreeBSD implement only file-to-socket copy support.

Thus you should get ENOTSOCK (Socket operation on non-socket).
Unfortunately, our FileChannelImpl.c swapped the srcFD and dstFD
descriptor arguments to our sendfile() syscall, resulting in EBADF (Bad
file descriptor).

Greg Lewis asked me to try out the attached patch for FreeBSD's native
jdk-1.4.1 (ports/java/jdk14).  I've tested it, and it works around the
problem nicely.

With a patched JDK (and updated ${idea.install.dir}/jre), IDEA no longer
exhibits the broken copy behaviour ("Bad file descriptor" caching jars
and copying resources).

We'll raise the issue on freebsd-arch, in case there's interest in
file-to-file sendfile() copy support.  If not, the long-term solution
here is probably to detect whether dstFD is a socket descriptor and use
sendfile() in that case, falling back to pread() and write() otherwise.

But for those of you who can't wait, the patch should tide you over.
When it's committed to the ports tree, it'll probably take the name
ports/java/jdk14/files/patch-FileChannelImpl.c .

Big thanks to Greg, Alexey and the ever-helpful Serge Baranov at
IntelliJ.

Ciao,
Sheldon.

Index: j2se/src/solaris/native/sun/nio/ch/FileChannelImpl.c
===================================================================
RCS file: /var/jcvs/javasrc_1_4_scsl/j2se/src/solaris/native/sun/nio/ch/FileChannelImpl.c,v
retrieving revision 1.5
diff -u -r1.5 FileChannelImpl.c
--- ../../j2se/src/solaris/native/sun/nio/ch/FileChannelImpl.c	6 Jun 2003 15:31:42 -0000	1.5
+++ ../../j2se/src/solaris/native/sun/nio/ch/FileChannelImpl.c	18 Jul 2003 16:49:33 -0000
@@ -186,15 +186,28 @@
     }
     return n;
 #elif defined(__FreeBSD__)
+#include <errno.h>
+#include <stdlib.h>
     /*
      * XXXBSD: make sure that we're returning what java class may understand
      */
+    void *buf;
     off_t offset = (off_t)position;
-    int n = sendfile(dstFD, srcFD, offset, (size_t)count, NULL, NULL, 0);
-    if (n < 0) {
+    int r, w;
+
+    buf = malloc(4096);
+    while ((r = pread(srcFD, buf, 4096, offset)) > 0) {
+	w = write(dstFD, buf, r);
+        if (w == -1)
+            break;
+        offset += w;
+    } 
+    free(buf);
+    if (r == -1 || w == -1) {
+	fprintf(stderr, "%d %d %d %d %d\n", srcFD, dstFD, r, w, errno);
 	JNU_ThrowIOExceptionWithLastError(env, "Transfer failed");
     }
-    return n;
+    return (offset - position);
 #else
     return IOS_UNSUPPORTED;
 #endif


More information about the freebsd-java mailing list