? gotk.class ? gotk.java ? io-nio-final.patch ? io-nio.patch ? io-nio2.patch ? lib/org/omg ? lib/org/relaxng ? lib/org/ietf/jgss/ChannelBinding.class ? lib/org/ietf/jgss/GSSContext.class ? lib/org/ietf/jgss/GSSCredential.class ? lib/org/ietf/jgss/GSSException.class ? lib/org/ietf/jgss/GSSManager.class ? lib/org/ietf/jgss/GSSName.class ? lib/org/ietf/jgss/MessageProp.class ? lib/org/ietf/jgss/MessagesBundle.properties ? lib/org/ietf/jgss/Oid.class ? lib/org/w3c/dom/Attr.class ? lib/org/w3c/dom/CDATASection.class ? lib/org/w3c/dom/CharacterData.class ? lib/org/w3c/dom/Comment.class ? lib/org/w3c/dom/DOMConfiguration.class ? lib/org/w3c/dom/DOMError.class ? lib/org/w3c/dom/DOMErrorHandler.class ? lib/org/w3c/dom/DOMException.class ? lib/org/w3c/dom/DOMImplementation.class ? lib/org/w3c/dom/DOMImplementationList.class ? lib/org/w3c/dom/DOMImplementationSource.class ? lib/org/w3c/dom/DOMLocator.class ? lib/org/w3c/dom/DOMStringList.class ? lib/org/w3c/dom/Document.class ? lib/org/w3c/dom/DocumentFragment.class ? lib/org/w3c/dom/DocumentType.class ? lib/org/w3c/dom/Element.class ? lib/org/w3c/dom/Entity.class ? lib/org/w3c/dom/EntityReference.class ? lib/org/w3c/dom/NameList.class ? lib/org/w3c/dom/NamedNodeMap.class ? lib/org/w3c/dom/Node.class ? lib/org/w3c/dom/NodeList.class ? lib/org/w3c/dom/Notation.class ? lib/org/w3c/dom/ProcessingInstruction.class ? lib/org/w3c/dom/Text.class ? lib/org/w3c/dom/TypeInfo.class ? lib/org/w3c/dom/UserDataHandler.class ? lib/org/w3c/dom/bootstrap ? lib/org/w3c/dom/css ? lib/org/w3c/dom/events ? lib/org/w3c/dom/html2 ? lib/org/w3c/dom/ls ? lib/org/w3c/dom/ranges ? lib/org/w3c/dom/stylesheets ? lib/org/w3c/dom/traversal ? lib/org/w3c/dom/views ? lib/org/w3c/dom/xpath ? lib/org/xml/sax/AttributeList.class ? lib/org/xml/sax/Attributes.class ? lib/org/xml/sax/ContentHandler.class ? lib/org/xml/sax/DTDHandler.class ? lib/org/xml/sax/DocumentHandler.class ? lib/org/xml/sax/EntityResolver.class ? lib/org/xml/sax/ErrorHandler.class ? lib/org/xml/sax/HandlerBase.class ? lib/org/xml/sax/InputSource.class ? lib/org/xml/sax/Locator.class ? lib/org/xml/sax/Parser.class ? lib/org/xml/sax/SAXException.class ? lib/org/xml/sax/SAXNotRecognizedException.class ? lib/org/xml/sax/SAXNotSupportedException.class ? lib/org/xml/sax/SAXParseException.class ? lib/org/xml/sax/XMLFilter.class ? lib/org/xml/sax/XMLReader.class ? lib/org/xml/sax/ext ? lib/org/xml/sax/helpers Index: ChangeLog =================================================================== RCS file: /cvsroot/classpath/classpath/ChangeLog,v retrieving revision 1.8550 diff -u -r1.8550 ChangeLog --- ChangeLog 16 Sep 2006 17:54:42 -0000 1.8550 +++ ChangeLog 17 Sep 2006 06:17:09 -0000 @@ -1,3 +1,329 @@ +<<<<<<< ChangeLog +2006-09-16 Casey Marshall + + * NEWS: updated. + * configure.ac (AC_CHECK_HEADERS): check for `sys/event.h'. + (AC_CHECK_FUNCS): add checks for readv, writev, getifaddrs, + kqueue, and kevent. + (HAVE_INET6): define if IPv6 is supported. + * gnu/java/net/PlainDatagramSocketImpl.java (channel): new field. + (native_fd): removed. + (impl): new field. + (): throw IOException; initialize fields. + (finalize): removed. + (getNativeFD): removed. + (bind): use `PlainSocketImpl.bind.' + (create): use `PlainSocketImpl.initSocket.' + (disconnect): use `PlainSocketImpl.disconnect.' + (getLocalPort): new method. + (send): use `VMChannel.send.' + (receive): use `VMChannel.receive.' + (setOption): use `PlainSocketImpl.setOption.' + (getOption): use `PlainSocketImpl.getOption.' + (close): use `VMChannel.State.close.' + (join): use `PlainSocketImpl.join.' + (leave): use `PlainSocketImpl.leave.' + (joinGroup, leaveGroup): implemented. + * gnu/java/net/PlainSocketImpl.java: make non-final. + (native_fd): removed. + (impl): new field. + (channel): new field. + (): initialize `impl.' + (finalize, getNativeFD): removed. + (setOption): use `PlainSocketImpl.setOption.' + (getOption): use `PlainSocketImpl.getOption.' + (shutdownInput): use `PlainSocketImpl.shutdownInput.' + (shutdownOutput): use `PlainSocketImpl.shutdownOutput.' + (create): create `channel,' initialize `impl's native state. + (connect): use `connect(SocketAddress, int).' + (connect): use `SocketChannelImpl.connect;' initialize `address' + and `port.' + (bind): use `VMPlainSocketImpl.bind.' + (listen): use `VMPlainSocketImpl.listen.' + (accept): use `SocketChannelImpl.accept.' + (available): use `VMChannel.available.' + (close): use `PlainSocketImpl.close.' + (sendUrgentData): use `PlainSocketImpl.sendUrgentData.' + (getVMChannel, getInetAddress, getLocalPort, getLocalAddress, + getPort): new methods. + (SocketInputStream.read): use `VMChannel.read.' + (SocketInputStream.read): use `SocketChannel.read.' + (SocketOutputStream.write): use `VMChannel.write.' + (SocketOutputStream.write): use `SocketChannel.write.' + * gnu/java/nio/DatagramChannelImpl.java: implement VMChannel. + (channel): new field. + (): initialize `channel.' + (implCloseSelectableChannel): use `VMChannel.close.' + (implConfigureBlocking): use `VMChannel.setBlocking.' + (connect): use `VMChannel.connect.' + (disconnect): use `VMChannel.disconnect.' + (isConnected): use `VMChannel.getPeerAddress.' + (write): use `VMChannel.write.' + (write): use `VMChannel.writeGathering.' + (read): use `VMChannel.read.' + (read): use `VMChannel.readScattering.' + (receive): use `VMChannel.receive.' + (send): use `VMChannel.send.' + (getVMChannel): new method. + * gnu/java/nio/DatagramChannelSelectionKey.java (getNativeFD): + access native FD through VMChannel.State. + * gnu/java/nio/FileChannelImpl.java: moved from + gnu/java/nio/channels/FileChannelImpl.java. + * gnu/java/nio/FileLockImpl.java: fix imports. + * gnu/java/nio/KqueueSelectionKeyImpl.java: new file. + * gnu/java/nio/KqueueSelectorImpl.java: new file. + * gnu/java/nio/NIOSocket.java (impl): removed. + (channel): new field. + (): init superclass with a `NIOSocketImpl;' init `channel.' + (getPlainSocketImpl, setChannel): removed. + (isConnected): new method. + * gnu/java/nio/NIOSocketImpl.java: new file. + * gnu/java/nio/PipeImpl.java (SourceChannelImpl): implement + `VMChannelOwner.' + (SourceChannelImpl.native_fd): removed. + (SourceChannelImpl.): init with a `VMChannel.' + (SourceChannelImpl.getNativeFD): removed. + (SourceChannelImpl.getVMChannel): new method. + (SourceChannelImpl.implCloseSelectableChannel): implement. + (SinkChannelImpl): implement `VMChannelOwner.' + (SinkChannelImpl.native_fd): removed. + (SinkChannelImpl.): init with a `VMChannel.' + (SinkChannelImpl.implCloseSelectableChannel): implement. + (SinkChannelImpl.getNativeFD): removed. + (SinkChannelImpl.getVMChannel): new method. + * gnu/java/nio/SelectionKeyImpl.java (getNativeFD): mark + deprecated. + * gnu/java/nio/SelectorProviderImpl.java (SELECTOR_IMPL_KQUEUE, + SELECTOR_IMPL_EPOLL, SELECTOR_IMPL): new constants. + (openSelector): return kqueue selector if available. + * gnu/java/nio/ServerSocketChannelImpl.java: implement + `VMChannelOwner.' + (channel): new field. + (): init `channel.' + (finalizer): check if the `VMChannel.State' is valid. + (implCloseSelectableChannel): use `VMChannel.close.' + (implConfigureBlocking): use `VMChannel.setBlocking.' + (accept): use `VMChannel.accept.' + (getVMChannel): new method. + * gnu/java/nio/ServerSocketChannelSelectionKey.java (getNativeFD): + access native FD through `VMChannel.State.' + * gnu/java/nio/SocketChannelImpl.java: implement `VMChannelOwner.' + (impl): removed. + (channel, connected, connectAddress): new field. + (): new constructors. + (getPlainSocketImpl): removed. + (implCloseSelectableChannel): use `VMChannel.close.' + (implConfigureBlocking): use `VMChannel.setBlocking.' + (connect): use `connect(SocketAddress,int).' + (connect): use `VMChannel.connect.' + (finishConnect): don't use a selector. + (isConnected): use `VMChannel.getPeerAddress.' + (read): use `VMChannel.read.' + (read): use `VMChannel.readScattering.' + (write): use `VMChannel.write.' + (write): use `VMChannel.writeGathering.' + (getVMChannel): new method. + * gnu/java/nio/SocketChannelSelectionKey.java (getNativeFD): get + native FD from `VMChannel.State.' + * gnu/java/nio/SocketChannelSelectionKeyImpl.java (getNativeFD): + get native FD from `VMChannel.State.' + * gnu/java/nio/VMChannelOwner.java: new file. + * gnu/java/nio/channels/FileChannelImpl.java: removed. + * include/Makefile.am: generate `gnu_java_nio_FileChannelImpl.h' + and `gnu_java_nio_KqueueSelectorImpl.h;' don't generate + `gnu_java_nio_channels_FileChannelImpl.h.' + * include/gnu_java_net_VMPlainSocketImpl.h: regenerated. + * include/gnu_java_nio_FileChannelImpl.h: new file. + * include/gnu_java_nio_KqueueSelectorImpl.h: new file. + * include/gnu_java_nio_VMChannel.h: regenerated. + * include/gnu_java_nio_VMPipe.h: regenerated. + * include/java_net_VMNetworkInterface.h: regenerated. + * java/io/FileDescriptor.java: fix imports. + * java/io/FileInputStream.java (): handle exceptions. + (read): wrap the destination arary. + * java/io/FileOutputStream.java (): handle exceptions. + (write): wrap the source array. + * java/io/RandomAccessFile.java (): handle exceptions. + * java/net/DatagramSocket.java (): handle exceptions. + (receive): handle length/port setting. + (connect): bind to any address/port if the argument is null. + * java/net/NetworkInterface.java (name, inetAddress): removed. + (netif): new field. + (): make private. + (getName): return `netif.name.' + (getInetAddresses): access `netif.addresses.' + (getDisplayName): return `netif.name.' + (getByName, getByAddress): handle changes to `VMNetworkInterface.' + (condense): removed. + (getNetworkInterfaces): handle changes to `VMNetworkInterface.' + (equals): compare `netif' fields. + (hashCode): get hash codes from `netif.' + (toString): use a StringBuffer. + * java/net/ServerSocket.java (close): don't set `impl' to null. + (isClosed): use `VMChannel.State.isClosed.' + * java/net/Socket.java (getLocalAddress): don't use `getOption' if + the `SocketImpl' is a `PlainSocketImpl.' + (close): just close the `impl.' + (toString): use `super.toString' in the value we return. + (isConnected): just access `impl,' not `getImpl.' + (isBound): use `PlainSocketImpl' methods if we can. + (isClosed): look at `VMChannel.State.' + * native/jni/classpath/jcl.c (JNI_OnLoad): new function. + (JCL_NewRawDataObject): don't initialize cached fields here; throw + an exception if they were not. + (JCL_GetRawData): throw an exception if cached fields weren't + created. + * native/jni/java-lang/java_lang_VMProcess.c: handle + FileChannelImpl move. + * native/jni/java-net/gnu_java_net_VMPlainSocketImpl.c + (IO_EXCEPTION, SOCKET_EXCEPTION, BIND_EXCEPTION, + THROW_NO_NETWORK): new macros. + (Java_gnu_java_net_VMPlainSocketImpl_bind): reipmlemented. + (Java_gnu_java_net_VMPlainSocketImpl_bind6): new function. + (Java_gnu_java_net_VMPlainSocketImpl_listen): reimplemented. + (java_sockopt): new enum. + (Java_gnu_java_net_VMPlainSocketImpl_setOption): reimplemented. + (Java_gnu_java_net_VMPlainSocketImpl_getOption): reimplemented. + (Java_gnu_java_net_VMPlainSocketImpl_shutdownInput): + reimplemented. + (Java_gnu_java_net_VMPlainSocketImpl_shutdownOutput): + reimplemented. + (Java_gnu_java_net_VMPlainSocketImpl_sendUrgentData): new + function. + (Java_gnu_java_net_VMPlainSocketImpl_join): new function. + (Java_gnu_java_net_VMPlainSocketImpl_join6): new function. + (Java_gnu_java_net_VMPlainSocketImpl_read): removed. + (Java_gnu_java_net_VMPlainSocketImpl_leave): new function. + (Java_gnu_java_net_VMPlainSocketImpl_leave6): new function. + (Java_gnu_java_net_VMPlainSocketImpl_joinGroup): new function. + (Java_gnu_java_net_VMPlainSocketImpl_write): removed. + (Java_gnu_java_net_VMPlainSocketImpl_joinGroup6): new function. + (Java_gnu_java_net_VMPlainSocketImpl_leaveGroup): new function. + (Java_gnu_java_net_VMPlainSocketImpl_leaveGroup6): new function. + (getif_address): new function. + (getif_index): new function. + * native/jni/java-net/java_net_VMNetworkInterface.c + (java_net_VMNetworkInterface_init, + java_net_VMNetworkInterface_addAddress): new file-scope globals. + (Java_java_net_VMNetworkInterface_initIds): new function. + (struct netif_entry): new struct. + (free_netif_list): new function. + (Java_java_net_VMNetworkInterface_getInterfaces): removed. + (Java_java_net_VMNetworkInterface_getVMInterfaces): new function. + * native/jni/java-nio/Makefile.am (libjavanio_la_SOURCES): remove + gnu_java_nio_channels_FileChannelImpl.c, add + gnu_java_nio_KqueueSelectorImpl.c. + * native/jni/java-nio/gnu_java_nio_KqueueSelectorImpl.c: new file. + * native/jni/java-nio/gnu_java_nio_VMChannel.c + (INTERRUPTED_IO_EXCEPTION, SOCKET_TIMEOUT_EXCEPTION, ALIGN_UP, + ALIGN_DOWN): new macros. + (JCL_init_buffer): get the address through GetDirectBufferAddress + if possible. + (Java_gnu_java_nio_VMChannel_stdin_1fd, + Java_gnu_java_nio_VMChannel_stdout_1fd, + Java_gnu_java_nio_VMChannel_stderr_1fd): new functions. + (Java_gnu_java_nio_VMChannel_setBlocking): fix setting blocking + value. + (Java_gnu_java_nio_VMChannel_read): renamed... + (Java_gnu_java_nio_VMChannel_read__ILjava_nio_ByteBuffer_2): to + this; handle interrupted IO; add HAVE_READ check. + (Java_gnu_java_nio_VMChannel_write): renamed... + (Java_gnu_java_nio_VMChannel_write__ILjava_nio_ByteBuffer_2): to + this; handle zero-length write; add HAVE_WRITE check. + (Java_gnu_java_nio_VMChannel_receive): new function. + (Java_gnu_java_nio_VMChannel_send): new function. + (Java_gnu_java_nio_VMChannel_send6): new function. + (Java_gnu_java_nio_VMChannel_read__I): new function. + (Java_gnu_java_nio_VMChannel_write__II): new function. + (Java_gnu_java_nio_VMChannel_socket): new function. + (Java_gnu_java_nio_VMChannel_connect): new function. + (Java_gnu_java_nio_VMChannel_connect6): new function. + (Java_gnu_java_nio_VMChannel_getsockname): new function. + (Java_gnu_java_nio_VMChannel_getpeername): new function. + (Java_gnu_java_nio_VMChannel_accept): new function. + (Java_gnu_java_nio_VMChannel_disconnect): new function. + (Java_gnu_java_nio_VMChannel_close): new function. + (Java_gnu_java_nio_VMChannel_available): new function. + (FileChannel_mode): new enum. + (Java_gnu_java_nio_VMChannel_open): new function. + (Java_gnu_java_nio_VMChannel_position): new function. + (Java_gnu_java_nio_VMChannel_seek): new function. + (Java_gnu_java_nio_VMChannel_truncate): new funciton. + (Java_gnu_java_nio_VMChannel_lock): new function. + (Java_gnu_java_nio_VMChannel_unlock): new function. + (Java_gnu_java_nio_VMChannel_size): new function. + (Java_gnu_java_nio_VMChannel_map): new function. + (Java_gnu_java_nio_VMChannel_flush): new function. + * native/jni/java-nio/gnu_java_nio_VMPipe.c + (Java_gnu_java_nio_VMPipe_init): removed. + (Java_gnu_java_nio_VMPipe_pipe0): new function. + * native/jni/java-nio/javanio.c: new file. + * native/jni/java-nio/javanio.h: new file. + * native/jni/native-lib/cpnet.c (cpnet_getHostByName): fix for + systems without `gethostbyname_r.' + * vm/reference/gnu/java/net/VMPlainSocketImpl.java (nfd): new + field. + (, ): new constructors. + (setOption, getOption): make instance methods; defer to native + implementation. + (connect): removed. + (bind): make an instance method; defer to native methods. + (accept): removed. + (available): removed. + (listen): make an instance method; defer to native method. + (read): removed. + (join, leave): new methods. + (write): removed. + (joinGroup, leaveGroup): new methods. + (shutdownInput, shutdownOutput): make instance methods. + (sendUrgentData): removed. + (State): new class. + * vm/reference/gnu/java/nio/VMChannel.java: make final. + (fd): removed. + (nfd): new field. + (): new, public constructors. + (getVMChannel): methods removed. + (getState, getStdin, getStdout, getStderr, stdin_fd, stdout_fd, + stderr_fd): new methods. + (setBlocking): make an instance method. + (available): new method. + (read): get native fd from `nfd.' + (read): new single-byte read method. + (readScattering): get native fd from `nfd.' + (receive): new method. + (write, writeGathering): get native fd from `nfd.' + (send): new method. + (write): new single-byte write method. + (initSocket): new method. + (connect): new method. + (disconnect): new method. + (getLocalAddress): new method. + (getPeerAddress): new method. + (accept): new method. + (openFile): new method. + (position): new method. + (seek): new method. + (truncate): new method. + (lock): new method. + (unlock): new method. + (size): new method. + (map): new method. + (flush): new method. + (close): new method. + (State): new class. + (Kind): new class. + * vm/reference/gnu/java/nio/VMPipe.java (init): removed. + (pipe, pipe0): new method. + * vm/reference/java/net/VMNetworkInterface.java (name, addresses): + new fields. + (): call `initIds.' + (initIds): new method. + (getInterfaces): removed. + (getVMInterfaces): new method. + (addAddress): new method. + * vm/reference/java/nio/channels/VMChannels.java: fix imports. + +======= 2006-09-16 Chris Burdess Fixes PR 28572. @@ -9,6 +335,7 @@ Fixes PR 27293. * gnu/xml/dom/DomNode.java: Increment length of node during insert. +>>>>>>> 1.8550 2006-09-14 Michael Koch * include/gnu_java_awt_peer_gtk_CairoGraphics2D.h: Recreated. Index: NEWS =================================================================== RCS file: /cvsroot/classpath/classpath/NEWS,v retrieving revision 1.167 diff -u -r1.167 NEWS --- NEWS 8 Sep 2006 08:59:57 -0000 1.167 +++ NEWS 17 Sep 2006 06:17:10 -0000 @@ -17,6 +17,26 @@ vm/reference/gnu/classpath/VMStackWalker.java. VMs are encouraged to provide a more efficient implementation. * Added aton method to vm/reference/java/net/VMInetAddress.java. +* NetworkInterface has been implemented for systems that provide the + `getifaddrs' function. +* A java.nio.channels.Selector implementation based on the + kqueue/kevent notification mechanism has been added for Mac OS X and + BSD systems. +* java.nio has been refactored to support more non-blocking operations + natively. Blocking IO classes have been refactored to call + non-blocking classes. Non-blocking accepts, connects, and + scatter-gather IO should now be better supported. + +Runtime interface changes: + +* java.net.VMNetworkInterface and java.net.NetworkInterface have been + updated to keep native-modified state in the former, and to simplify + the native code in our reference implementation. +* gnu.java.nio.VMChannel has been expanded to better support native + non-blocking IO. Most native state data (such as file descriptor + integers) has been abstracted away into private state in the runtime + interface. +* gnu.java.nio.VMPipe has been similarly changed. New in release 0.92 (Aug 9, 2006) Index: configure.ac =================================================================== RCS file: /cvsroot/classpath/classpath/configure.ac,v retrieving revision 1.182 diff -u -r1.182 configure.ac --- configure.ac 8 Sep 2006 08:59:57 -0000 1.182 +++ configure.ac 17 Sep 2006 06:17:10 -0000 @@ -356,7 +356,8 @@ crt_externs.h \ fcntl.h \ sys/mman.h \ - magic.h]) + magic.h \ + sys/event.h]) AC_EGREP_HEADER(uint32_t, stdint.h, AC_DEFINE(HAVE_INT32_DEFINED, 1, [Define to 1 if you have uint32_t])) AC_EGREP_HEADER(uint32_t, inttypes.h, AC_DEFINE(HAVE_INT32_DEFINED, 1, [Define to 1 if you have uint32_t])) @@ -365,7 +366,7 @@ AC_CHECK_FUNCS([ftruncate fsync select \ gethostname socket strerror fork pipe execve open close \ - lseek fstat read write htonl memset htons connect \ + lseek fstat read readv write writev htonl memset htons connect \ getsockname getpeername bind listen accept \ recvfrom send sendto setsockopt getsockopt time mktime \ gethostbyname_r localtime_r \ @@ -373,13 +374,20 @@ fcntl \ mmap munmap mincore msync madvise getpagesize sysconf \ lstat readlink \ - inet_aton inet_addr inet_pton \ - ]) + inet_aton inet_addr inet_pton \ + getifaddrs kqueue kevent]) LIBMAGIC= AC_CHECK_LIB(magic, magic_open, LIBMAGIC=-lmagic) AC_SUBST(LIBMAGIC) + AC_MSG_CHECKING([whether struct sockaddr_in6 is in netinet/in.h]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[struct sockaddr_in6 addr6;]])], + [AC_DEFINE(HAVE_INET6, 1, + [Define if inet6 structures are defined in netinet/in.h.]) + AC_MSG_RESULT(yes)], + [AC_MSG_RESULT(no)]) + AC_HEADER_TIME AC_STRUCT_TM AC_STRUCT_TIMEZONE Index: gnu/java/net/PlainDatagramSocketImpl.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/net/PlainDatagramSocketImpl.java,v retrieving revision 1.10 diff -u -r1.10 PlainDatagramSocketImpl.java --- gnu/java/net/PlainDatagramSocketImpl.java 4 Jan 2006 20:50:20 -0000 1.10 +++ gnu/java/net/PlainDatagramSocketImpl.java 17 Sep 2006 06:17:11 -0000 @@ -38,13 +38,18 @@ package gnu.java.net; +import gnu.java.nio.VMChannel; + import java.io.IOException; +import java.lang.reflect.Field; import java.net.DatagramPacket; import java.net.DatagramSocketImpl; import java.net.InetAddress; +import java.net.InetSocketAddress; import java.net.NetworkInterface; import java.net.SocketAddress; import java.net.SocketException; +import java.nio.ByteBuffer; /** * Written using on-line Java Platform 1.2 API Specification, as well @@ -62,11 +67,13 @@ */ public final class PlainDatagramSocketImpl extends DatagramSocketImpl { - + + private final VMChannel channel; + /** - * This is the actual underlying file descriptor + * The platform-specific socket implementation. */ - int native_fd = -1; + private final VMPlainSocketImpl impl; /** * Lock object to serialize threads wanting to receive @@ -81,25 +88,26 @@ /** * Default do nothing constructor */ - public PlainDatagramSocketImpl() + public PlainDatagramSocketImpl() throws IOException { - // Nothing to do here. + channel = new VMChannel(); + impl = new VMPlainSocketImpl(channel); } - protected void finalize() throws Throwable + /*protected void finalize() throws Throwable { synchronized (this) { - if (native_fd != -1) + if (channel.getState().isValid()) close(); } super.finalize(); - } + }*/ - public int getNativeFD() + /*public int getNativeFD() { return native_fd; - } + }*/ /** * Binds this socket to a particular port and interface @@ -109,20 +117,46 @@ * * @exception SocketException If an error occurs */ - protected synchronized void bind(int port, InetAddress addr) + protected synchronized void bind(int port, InetAddress addr) throws SocketException - { - VMPlainDatagramSocketImpl.bind(this, port, addr); - } + { + try + { + impl.bind(new InetSocketAddress(addr, port)); + } + catch (SocketException se) + { + throw se; + } + catch (IOException ioe) + { + SocketException se = new SocketException(); + se.initCause(ioe); + throw se; + } + } /** * Creates a new datagram socket * * @exception SocketException If an error occurs */ - protected synchronized void create() throws SocketException + protected synchronized void create() throws SocketException { - VMPlainDatagramSocketImpl.create(this); + try + { + channel.initSocket(false); + } + catch (SocketException se) + { + throw se; + } + catch (IOException ioe) + { + SocketException se = new SocketException(); + se.initCause(ioe); + throw se; + } } /** @@ -147,8 +181,14 @@ { synchronized (this) { - if (native_fd != -1) - close(); + try + { + if (channel.getState().isValid()) + channel.disconnect(); + } + catch (IOException ioe) + { + } } } @@ -181,6 +221,23 @@ return ((Integer) obj).intValue(); } + protected int getLocalPort() + { + if (channel == null) + return -1; + + try + { + InetSocketAddress local = channel.getLocalAddress(); + if (local == null) + return -1; + return local.getPort(); + } + catch (IOException ioe) + { + return -1; + } + } /** * Sends a packet of data to a remote host @@ -191,13 +248,19 @@ */ protected void send(DatagramPacket packet) throws IOException { - if (native_fd != -1) + synchronized (SEND_LOCK) { - synchronized(SEND_LOCK) - { - VMPlainDatagramSocketImpl.send(this, packet); - } - } + ByteBuffer buf = ByteBuffer.wrap(packet.getData(), + packet.getOffset(), + packet.getLength()); + InetAddress remote = packet.getAddress(); + int port = packet.getPort(); + if (remote == null) + throw new NullPointerException(); + if (port <= 0) + throw new SocketException("invalid port " + port); + channel.send(buf, new InetSocketAddress(remote, port)); + } } /** @@ -210,10 +273,16 @@ protected void receive(DatagramPacket packet) throws IOException { - synchronized(RECEIVE_LOCK) - { - VMPlainDatagramSocketImpl.receive(this, packet); - } + synchronized(RECEIVE_LOCK) + { + ByteBuffer buf = ByteBuffer.wrap(packet.getData(), + packet.getOffset(), + packet.getLength()); + SocketAddress addr = channel.receive(buf); + if (addr != null) + packet.setSocketAddress(addr); + packet.setLength(buf.position() - packet.getOffset()); + } } @@ -227,9 +296,9 @@ */ public synchronized void setOption(int option_id, Object val) throws SocketException - { - VMPlainDatagramSocketImpl.setOption(this, option_id, val); - } + { + impl.setOption(option_id, val); + } /** * Retrieves the value of an option on the socket @@ -242,16 +311,43 @@ */ public synchronized Object getOption(int option_id) throws SocketException - { - return VMPlainDatagramSocketImpl.getOption(this, option_id); - } + { + if (option_id == SO_BINDADDR) + { + try + { + InetSocketAddress local = channel.getLocalAddress(); + if (local == null) + return null; + return local.getAddress(); + } + catch (SocketException se) + { + throw se; + } + catch (IOException ioe) + { + SocketException se = new SocketException(); + se.initCause(ioe); + throw se; + } + } + return impl.getOption(option_id); + } /** * Closes the socket */ protected synchronized void close() { - VMPlainDatagramSocketImpl.close(this); + try + { + if (channel.getState().isValid()) + channel.close(); + } + catch (IOException ioe) + { + } } /** @@ -291,7 +387,7 @@ */ protected synchronized void join(InetAddress addr) throws IOException { - VMPlainDatagramSocketImpl.join(this,addr); + impl.join(addr); } /** @@ -303,7 +399,7 @@ */ protected synchronized void leave(InetAddress addr) throws IOException { - VMPlainDatagramSocketImpl.leave(this, addr); + impl.leave(addr); } /** @@ -323,12 +419,20 @@ public void joinGroup(SocketAddress address, NetworkInterface netIf) throws IOException { - VMPlainDatagramSocketImpl.joinGroup(this, address, netIf); + if (address == null) + throw new NullPointerException(); + if (!(address instanceof InetSocketAddress)) + throw new SocketException("unknown address type"); + impl.joinGroup((InetSocketAddress) address, netIf); } public void leaveGroup(SocketAddress address, NetworkInterface netIf) throws IOException { - VMPlainDatagramSocketImpl.leaveGroup(this, address, netIf); + if (address == null) + throw new NullPointerException(); + if (!(address instanceof InetSocketAddress)) + throw new SocketException("unknown address type"); + impl.leaveGroup((InetSocketAddress) address, netIf); } } Index: gnu/java/net/PlainSocketImpl.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/net/PlainSocketImpl.java,v retrieving revision 1.13 diff -u -r1.13 PlainSocketImpl.java --- gnu/java/net/PlainSocketImpl.java 4 Jan 2006 20:50:20 -0000 1.13 +++ gnu/java/net/PlainSocketImpl.java 17 Sep 2006 06:17:11 -0000 @@ -39,13 +39,24 @@ package gnu.java.net; +import gnu.java.nio.SelectorProviderImpl; +import gnu.java.nio.SocketChannelImpl; +import gnu.java.nio.VMChannel; +import gnu.java.security.action.GetSecurityPropertyAction; + +import java.io.EOFException; import java.io.InputStream; import java.io.IOException; +import java.io.InterruptedIOException; import java.io.OutputStream; import java.net.InetAddress; +import java.net.InetSocketAddress; import java.net.SocketAddress; import java.net.SocketException; import java.net.SocketImpl; +import java.net.SocketTimeoutException; +import java.nio.ByteBuffer; +import java.nio.channels.SocketChannel; /** * Written using on-line Java Platform 1.2 API Specification, as well @@ -63,17 +74,13 @@ * @author Nic Ferrier (nferrier@tapsellferrier.co.uk) * @author Aaron M. Renn (arenn@urbanophile.com) */ -public final class PlainSocketImpl extends SocketImpl +public class PlainSocketImpl extends SocketImpl { /** - * The OS file handle representing the socket. - * This is used for reads and writes to/from the socket and - * to close it. - * - * When the socket is closed this is reset to -1. + * The underlying plain socket VM implementation. */ - int native_fd = -1; + protected VMPlainSocketImpl impl; /** * A cached copy of the in stream for reading from the socket. @@ -90,7 +97,13 @@ * is being invoked on this socket. */ private boolean inChannelOperation; - + + /** + * The socket channel we use for IO operation. Package-private for + * use by inner classes. + */ + SocketChannelImpl channel; + /** * Indicates whether we should ignore whether any associated * channel is set to non-blocking mode. Certain operations @@ -117,29 +130,7 @@ */ public PlainSocketImpl() { - // Nothing to do here. - } - - protected void finalize() throws Throwable - { - synchronized (this) - { - if (native_fd != -1) - try - { - close(); - } - catch (IOException ex) - { - // Nothing we can do about it. - } - } - super.finalize(); - } - - public int getNativeFD() - { - return native_fd; + this.impl = new VMPlainSocketImpl(); } /** @@ -155,7 +146,29 @@ */ public void setOption(int optionId, Object value) throws SocketException { - VMPlainSocketImpl.setOption(this, optionId, value); + switch (optionId) + { + case IP_MULTICAST_IF: + case IP_MULTICAST_IF2: + throw new UnsupportedOperationException("FIXME"); + + case IP_MULTICAST_LOOP: + case SO_BROADCAST: + case SO_KEEPALIVE: + case SO_OOBINLINE: + case TCP_NODELAY: + case IP_TOS: + case SO_LINGER: + case SO_RCVBUF: + case SO_SNDBUF: + case SO_TIMEOUT: + case SO_REUSEADDR: + impl.setOption(optionId, value); + return; + + default: + throw new SocketException("cannot set option " + optionId); + } } /** @@ -171,17 +184,33 @@ */ public Object getOption(int optionId) throws SocketException { - return VMPlainSocketImpl.getOption(this, optionId); + if (optionId == SO_BINDADDR) + { + try + { + return channel.getVMChannel().getLocalAddress().getAddress(); + } + catch (IOException ioe) + { + SocketException se = new SocketException(); + se.initCause(ioe); + throw se; + } + } + if (optionId == IP_MULTICAST_IF || optionId == IP_MULTICAST_IF2) + throw new UnsupportedOperationException ("can't get option " + + optionId + " yet"); + return impl.getOption(optionId); } public void shutdownInput() throws IOException { - VMPlainSocketImpl.shutdownInput(this); + impl.shutdownInput(); } public void shutdownOutput() throws IOException { - VMPlainSocketImpl.shutdownOutput(this); + impl.shutdownOutput(); } /** @@ -195,7 +224,11 @@ */ protected synchronized void create(boolean stream) throws IOException { - VMPlainSocketImpl.create(this); + channel = new SocketChannelImpl(false); + VMChannel vmchannel = channel.getVMChannel(); + vmchannel.initSocket(stream); + channel.configureBlocking(true); + impl.getState().setChannelFD(vmchannel.getState()); } /** @@ -222,7 +255,7 @@ */ protected void connect(InetAddress addr, int port) throws IOException { - VMPlainSocketImpl.connect(this, addr, port); + connect(new InetSocketAddress(addr, port), 0); } /** @@ -236,7 +269,14 @@ protected synchronized void connect(SocketAddress address, int timeout) throws IOException { - VMPlainSocketImpl.connect(this, address, timeout); + if (channel == null) + create(true); + boolean connected = channel.connect(address, timeout); + if (!connected) + throw new SocketTimeoutException("connect timed out"); + InetSocketAddress addr = channel.getVMChannel().getPeerAddress(); + this.address = addr.getAddress(); + this.port = addr.getPort(); } /** @@ -251,7 +291,10 @@ protected synchronized void bind(InetAddress addr, int port) throws IOException { - VMPlainSocketImpl.bind(this, addr, port); + if (channel == null) + create(true); + impl.bind(new InetSocketAddress(addr, port)); + localport = channel.getVMChannel().getLocalAddress().getPort(); } /** @@ -267,7 +310,7 @@ protected synchronized void listen(int queuelen) throws IOException { - VMPlainSocketImpl.listen(this, queuelen); + impl.listen(queuelen); } /** @@ -279,7 +322,16 @@ protected synchronized void accept(SocketImpl impl) throws IOException { - VMPlainSocketImpl.accept(this, impl); + if (channel == null) + create(true); + if (!(impl instanceof PlainSocketImpl)) + throw new IOException("incompatible SocketImpl: " + + impl.getClass().getName()); + PlainSocketImpl that = (PlainSocketImpl) impl; + VMChannel c = channel.getVMChannel().accept(); + that.impl.getState().setChannelFD(c.getState()); + that.channel = new SocketChannelImpl(c); + that.setOption(SO_REUSEADDR, Boolean.TRUE); } /** @@ -292,7 +344,9 @@ */ protected int available() throws IOException { - return VMPlainSocketImpl.available(this); + if (channel == null) + throw new SocketException("not connected"); + return channel.getVMChannel().available(); } /** @@ -308,65 +362,13 @@ */ protected void close() throws IOException { - VMPlainSocketImpl.close(this); - } - - public void sendUrgentData(int data) - { - VMPlainSocketImpl.sendUrgendData(this, data); - } - - /** - * Internal method used by SocketInputStream for reading data from - * the connection. Reads up to len bytes of data into the buffer - * buf starting at offset bytes into the buffer. - * - * @return the actual number of bytes read or -1 if end of stream. - * - * @throws IOException if an error occurs - */ - protected int read(byte[] buf, int offset, int len) - throws IOException - { - return VMPlainSocketImpl.read(this, buf, offset, len); + if (impl.getState().isValid()) + impl.close(); } - /** - * Internal method used by SocketInputStream for reading data from - * the connection. Reads and returns one byte of data. - * - * @return the read byte - * - * @throws IOException if an error occurs - */ - protected int read() - throws IOException + public void sendUrgentData(int data) throws IOException { - return VMPlainSocketImpl.read(this); - } - - /** - * Internal method used by SocketOuputStream for writing data to - * the connection. Writes up to len bytes of data from the buffer - * buf starting at offset bytes into the buffer. - * - * @throws IOException If an error occurs - */ - protected void write(byte[] buf, int offset, int len) - throws IOException - { - VMPlainSocketImpl.write(this, buf, offset, len); - } - - /** - * Internal method used by SocketOuputStream for writing data to - * the connection. Writes up one byte to the socket. - * - * @throws IOException If an error occurs - */ - protected void write(int data) throws IOException - { - VMPlainSocketImpl.write(this, data); + impl.sendUrgentData(data); } /** @@ -400,6 +402,87 @@ return out; } + + public VMChannel getVMChannel() + { + if (channel == null) + return null; + return channel.getVMChannel(); + } + + /* (non-Javadoc) + * @see java.net.SocketImpl#getInetAddress() + */ + protected InetAddress getInetAddress() + { + if (channel == null) + return null; + try + { + InetSocketAddress remote = channel.getVMChannel().getPeerAddress(); + if (remote == null) + return null; + return remote.getAddress(); + } + catch (IOException ioe) + { + return null; + } + } + + /* (non-Javadoc) + * @see java.net.SocketImpl#getLocalPort() + */ + protected int getLocalPort() + { + if (channel == null) + return -1; + try + { + InetSocketAddress local = channel.getVMChannel().getLocalAddress(); + if (local == null) + return -1; + return local.getPort(); + } + catch (IOException ioe) + { + return -1; + } + } + + public InetSocketAddress getLocalAddress() + { + if (channel == null) + return null; + try + { + return channel.getVMChannel().getLocalAddress(); + } + catch (IOException ioe) + { + return null; + } + } + + /* (non-Javadoc) + * @see java.net.SocketImpl#getPort() + */ + protected int getPort() + { + if (channel == null) + return -1; + try + { + InetSocketAddress remote = channel.getVMChannel().getPeerAddress(); + if (remote == null) + return -1; + return remote.getPort(); + } + catch (IOException ioe) + { + return -1; + } + } /** * This class contains an implementation of InputStream for @@ -437,7 +520,23 @@ */ public int read() throws IOException { - return PlainSocketImpl.this.read(); + if (channel == null) + throw new SocketException("not connected"); + while (true) + { + try + { + return channel.getVMChannel().read(); + } + catch (SocketTimeoutException ste) + { + throw ste; + } + catch (InterruptedIOException iioe) + { + // Ignore; NIO may throw this; net io shouldn't + } + } } /** @@ -454,12 +553,24 @@ */ public int read (byte[] buf, int offset, int len) throws IOException { - int bytes_read = PlainSocketImpl.this.read (buf, offset, len); - - if (bytes_read == 0) - return -1; - - return bytes_read; + if (channel == null) + throw new SocketException("not connected"); + ByteBuffer b = ByteBuffer.wrap(buf, offset, len); + while (true) + { + try + { + return channel.read(b); + } + catch (SocketTimeoutException ste) + { + throw ste; + } + catch (InterruptedIOException iioe) + { + // Ignored; NIO may throw this; net IO not. + } + } } } @@ -495,7 +606,20 @@ */ public void write(int b) throws IOException { - PlainSocketImpl.this.write(b); + if (channel == null) + throw new SocketException("not connected"); + while (true) + { + try + { + channel.getVMChannel().write(b); + return; + } + catch (InterruptedIOException iioe) + { + // Ignored. + } + } } /** @@ -510,7 +634,21 @@ */ public void write (byte[] buf, int offset, int len) throws IOException { - PlainSocketImpl.this.write (buf, offset, len); + if (channel == null) + throw new SocketException("not connected"); + ByteBuffer b = ByteBuffer.wrap(buf, offset, len); + while (b.hasRemaining()) + { + try + { + if (channel.write(b) == -1) + throw new IOException("channel has been closed"); + } + catch (InterruptedIOException iioe) + { + // Ignored. + } + } } } } Index: gnu/java/nio/DatagramChannelImpl.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/nio/DatagramChannelImpl.java,v retrieving revision 1.15 diff -u -r1.15 DatagramChannelImpl.java --- gnu/java/nio/DatagramChannelImpl.java 27 Dec 2005 02:27:01 -0000 1.15 +++ gnu/java/nio/DatagramChannelImpl.java 17 Sep 2006 06:17:11 -0000 @@ -55,8 +55,10 @@ * @author Michael Koch */ public final class DatagramChannelImpl extends DatagramChannel + implements VMChannelOwner { private NIODatagramSocket socket; + private VMChannel channel; /** * Indicates whether this channel initiated whatever operation @@ -64,6 +66,16 @@ */ private boolean inChannelOperation; + protected DatagramChannelImpl (SelectorProvider provider) + throws IOException + { + super (provider); + socket = new NIODatagramSocket (new PlainDatagramSocketImpl(), this); + channel = new VMChannel(); + channel.initSocket(false); + configureBlocking(true); + } + /** * Indicates whether our datagram socket should ignore whether * we are set to non-blocking mode. Certain operations on our @@ -85,14 +97,6 @@ inChannelOperation = b; } - protected DatagramChannelImpl (SelectorProvider provider) - throws IOException - { - super (provider); - socket = new NIODatagramSocket (new PlainDatagramSocketImpl(), this); - configureBlocking(true); - } - public DatagramSocket socket () { return socket; @@ -101,13 +105,13 @@ protected void implCloseSelectableChannel () throws IOException { - socket.close (); + channel.close(); } protected void implConfigureBlocking (boolean blocking) throws IOException { - socket.setSoTimeout (blocking ? 0 : NIOConstants.DEFAULT_TIMEOUT); + channel.setBlocking(blocking); } public DatagramChannel connect (SocketAddress remote) @@ -116,20 +120,34 @@ if (!isOpen()) throw new ClosedChannelException(); - socket.connect (remote); + try + { + channel.connect((InetSocketAddress) remote, 0); + } + catch (ClassCastException cce) + { + throw new IOException("unsupported socked address type"); + } return this; } public DatagramChannel disconnect () throws IOException { - socket.disconnect (); + channel.disconnect(); return this; } - public boolean isConnected () + public boolean isConnected() { - return socket.isConnected (); + try + { + return channel.getPeerAddress() != null; + } + catch (IOException ioe) + { + return false; + } } public int write (ByteBuffer src) @@ -138,7 +156,7 @@ if (!isConnected ()) throw new NotYetConnectedException (); - return send (src, socket.getRemoteSocketAddress()); + return channel.write(src); } public long write (ByteBuffer[] srcs, int offset, int length) @@ -152,13 +170,11 @@ || (length < 0) || (length > (srcs.length - offset))) throw new IndexOutOfBoundsException(); - - long result = 0; - - for (int index = offset; index < offset + length; index++) - result += write (srcs [index]); - return result; + /* We are connected, meaning we will write these bytes to + * the host we connected to, so we don't need to explicitly + * give the host. */ + return channel.writeGathering(srcs, offset, length); } public int read (ByteBuffer dst) @@ -167,9 +183,7 @@ if (!isConnected ()) throw new NotYetConnectedException (); - int remaining = dst.remaining(); - receive (dst); - return remaining - dst.remaining(); + return channel.read(dst); } public long read (ByteBuffer[] dsts, int offset, int length) @@ -184,12 +198,8 @@ || (length > (dsts.length - offset))) throw new IndexOutOfBoundsException(); - long result = 0; - - for (int index = offset; index < offset + length; index++) - result += read (dsts [index]); - - return result; + /* Likewise, see the comment int write above. */ + return channel.readScattering(dsts, offset, length); } public SocketAddress receive (ByteBuffer dst) @@ -200,49 +210,12 @@ try { - DatagramPacket packet; - int len = dst.remaining(); - - if (dst.hasArray()) - { - packet = new DatagramPacket (dst.array(), - dst.arrayOffset() + dst.position(), - len); - } - else - { - packet = new DatagramPacket (new byte [len], len); - } - - boolean completed = false; - - try - { - begin(); - setInChannelOperation(true); - socket.receive (packet); - completed = true; - } - finally - { - end (completed); - setInChannelOperation(false); - } - - if (!dst.hasArray()) - { - dst.put (packet.getData(), packet.getOffset(), packet.getLength()); - } - else - { - dst.position (dst.position() + packet.getLength()); - } - - return packet.getSocketAddress(); + begin(); + return channel.receive(dst); } - catch (SocketTimeoutException e) + finally { - return null; + end(true); } } @@ -252,46 +225,18 @@ if (!isOpen()) throw new ClosedChannelException(); - if (target instanceof InetSocketAddress - && ((InetSocketAddress) target).isUnresolved()) - throw new IOException("Target address not resolved"); - - byte[] buffer; - int offset = 0; - int len = src.remaining(); + if (!(target instanceof InetSocketAddress)) + throw new IOException("can only send to inet socket addresses"); - if (src.hasArray()) - { - buffer = src.array(); - offset = src.arrayOffset() + src.position(); - } - else - { - buffer = new byte [len]; - src.get (buffer); - } - - DatagramPacket packet = new DatagramPacket (buffer, offset, len, target); - - boolean completed = false; - try - { - begin(); - setInChannelOperation(true); - socket.send(packet); - completed = true; - } - finally - { - end (completed); - setInChannelOperation(false); - } - - if (src.hasArray()) - { - src.position (src.position() + len); - } + InetSocketAddress dst = (InetSocketAddress) target; + if (dst.isUnresolved()) + throw new IOException("Target address not resolved"); - return len; + return channel.send(src, dst); + } + + public VMChannel getVMChannel() + { + return channel; } } Index: gnu/java/nio/DatagramChannelSelectionKey.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/nio/DatagramChannelSelectionKey.java,v retrieving revision 1.3 diff -u -r1.3 DatagramChannelSelectionKey.java --- gnu/java/nio/DatagramChannelSelectionKey.java 2 Jul 2005 20:32:13 -0000 1.3 +++ gnu/java/nio/DatagramChannelSelectionKey.java 17 Sep 2006 06:17:11 -0000 @@ -38,6 +38,7 @@ package gnu.java.nio; +import java.io.IOException; import java.nio.channels.spi.AbstractSelectableChannel; /** @@ -52,10 +53,16 @@ super (channel, selector); } + // FIXME don't use file descriptor integers public int getNativeFD() { - NIODatagramSocket socket = - (NIODatagramSocket) ((DatagramChannelImpl) ch).socket(); - return socket.getPlainDatagramSocketImpl().getNativeFD(); + try + { + return ((DatagramChannelImpl) ch).getVMChannel().getState().getNativeFD(); + } + catch (IOException ioe) + { + throw new IllegalStateException(ioe); + } } } Index: gnu/java/nio/FileChannelImpl.java =================================================================== RCS file: gnu/java/nio/FileChannelImpl.java diff -N gnu/java/nio/FileChannelImpl.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ gnu/java/nio/FileChannelImpl.java 17 Sep 2006 06:17:11 -0000 @@ -0,0 +1,572 @@ +/* FileChannelImpl.java -- + Copyright (C) 2002, 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. */ + + +package gnu.java.nio; + +import gnu.classpath.Configuration; +import gnu.java.nio.FileLockImpl; +import gnu.java.nio.VMChannel; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.MappedByteBuffer; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; +import java.nio.channels.NonReadableChannelException; +import java.nio.channels.NonWritableChannelException; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; + +/** + * This file is not user visible ! + * But alas, Java does not have a concept of friendly packages + * so this class is public. + * Instances of this class are created by invoking getChannel + * Upon a Input/Output/RandomAccessFile object. + */ +public final class FileChannelImpl extends FileChannel +{ + // These are mode values for open(). + public static final int READ = 1; + public static final int WRITE = 2; + public static final int APPEND = 4; + + // EXCL is used only when making a temp file. + public static final int EXCL = 8; + public static final int SYNC = 16; + public static final int DSYNC = 32; + + public static final FileChannelImpl in; + public static final FileChannelImpl out; + public static final FileChannelImpl err; + + //private static native void init(); + + static + { + if (Configuration.INIT_LOAD_LIBRARY) + { + System.loadLibrary("javanio"); + } + + //init(); + + FileChannelImpl ch = null; + try + { + ch = new FileChannelImpl(VMChannel.getStdin(), READ); + } + catch (IOException ioe) + { + throw new Error(ioe); + } + in = ch; + + ch = null; + try + { + ch = new FileChannelImpl(VMChannel.getStdout(), WRITE); + } + catch (IOException ioe) + { + throw new Error(ioe); + } + out = ch; + + ch = null; + try + { + ch = new FileChannelImpl(VMChannel.getStderr(), WRITE); + } + catch (IOException ioe) + { + throw new Error(ioe); + } + err = ch; + } + + /** + * This is the actual native file descriptor value + */ + private VMChannel ch; + + private int mode; + + final String description; + + /* Open a file. MODE is a combination of the above mode flags. */ + /* This is a static factory method, so that VM implementors can decide + * substitute subclasses of FileChannelImpl. */ + public static FileChannelImpl create(File file, int mode) + throws IOException + { + return new FileChannelImpl(file, mode); + } + + private FileChannelImpl(File file, int mode) + throws IOException + { + String path = file.getPath(); + description = path; + this.mode = mode; + this.ch = new VMChannel(); + ch.openFile(path, mode); + + // First open the file and then check if it is a a directory + // to avoid race condition. + if (file.isDirectory()) + { + try + { + close(); + } + catch (IOException e) + { + /* ignore it */ + } + + throw new FileNotFoundException(description + " is a directory"); + } + } + + /** + * Constructor for default channels in, out and err. + * + * Used by init() (native code). + * + * @param fd the file descriptor (0, 1, 2 for stdin, stdout, stderr). + * + * @param mode READ or WRITE + */ + FileChannelImpl (VMChannel ch, int mode) + { + this.mode = mode; + this.description = "descriptor(" + ch.getState() + ")"; + this.ch = ch; + } + + public int available() throws IOException + { + return ch.available(); + } + + private long implPosition() throws IOException + { + return ch.position(); + } + + private void seek(long newPosition) throws IOException + { + ch.seek(newPosition); + } + + private void implTruncate(long size) throws IOException + { + ch.truncate(size); + } + + public void unlock(long pos, long len) throws IOException + { + ch.unlock(pos, len); + } + + public long size () throws IOException + { + return ch.size(); + } + + protected void implCloseChannel() throws IOException + { + ch.close(); + } + + /** + * Makes sure the Channel is properly closed. + */ + protected void finalize() throws IOException + { + if (ch.getState().isValid()) + close(); + } + + public int read (ByteBuffer dst) throws IOException + { + return ch.read(dst); + } + + public int read (ByteBuffer dst, long position) + throws IOException + { + if (position < 0) + throw new IllegalArgumentException ("position: " + position); + long oldPosition = implPosition (); + position (position); + int result = read(dst); + position (oldPosition); + + return result; + } + + public int read() throws IOException + { + return ch.read(); + } + + public long read (ByteBuffer[] dsts, int offset, int length) + throws IOException + { + return ch.readScattering(dsts, offset, length); + } + + public int write (ByteBuffer src) throws IOException + { + return ch.write(src); + } + + public int write (ByteBuffer src, long position) + throws IOException + { + if (position < 0) + throw new IllegalArgumentException ("position: " + position); + + if (!isOpen ()) + throw new ClosedChannelException (); + + if ((mode & WRITE) == 0) + throw new NonWritableChannelException (); + + int result; + long oldPosition; + + oldPosition = implPosition (); + seek (position); + result = write(src); + seek (oldPosition); + + return result; + } + + public void write (int b) throws IOException + { + ch.write(b); + } + + public long write(ByteBuffer[] srcs, int offset, int length) + throws IOException + { + return ch.writeGathering(srcs, offset, length); + } + + public MappedByteBuffer map (FileChannel.MapMode mode, + long position, long size) + throws IOException + { + char nmode = 0; + if (mode == MapMode.READ_ONLY) + { + nmode = 'r'; + if ((this.mode & READ) == 0) + throw new NonReadableChannelException(); + } + else if (mode == MapMode.READ_WRITE || mode == MapMode.PRIVATE) + { + nmode = mode == MapMode.READ_WRITE ? '+' : 'c'; + if ((this.mode & WRITE) != WRITE) + throw new NonWritableChannelException(); + if ((this.mode & READ) != READ) + throw new NonReadableChannelException(); + } + else + throw new IllegalArgumentException ("mode: " + mode); + + if (position < 0 || size < 0 || size > Integer.MAX_VALUE) + throw new IllegalArgumentException ("position: " + position + + ", size: " + size); + return ch.map(nmode, position, (int) size); + } + + /** + * msync with the disk + */ + public void force (boolean metaData) throws IOException + { + if (!isOpen ()) + throw new ClosedChannelException (); + + ch.flush(metaData); + } + + // like transferTo, but with a count of less than 2Gbytes + private int smallTransferTo (long position, int count, + WritableByteChannel target) + throws IOException + { + ByteBuffer buffer; + try + { + // Try to use a mapped buffer if we can. If this fails for + // any reason we'll fall back to using a ByteBuffer. + buffer = map (MapMode.READ_ONLY, position, count); + } + catch (IOException e) + { + buffer = ByteBuffer.allocate (count); + read (buffer, position); + buffer.flip(); + } + + return target.write (buffer); + } + + public long transferTo (long position, long count, + WritableByteChannel target) + throws IOException + { + if (position < 0 + || count < 0) + throw new IllegalArgumentException ("position: " + position + + ", count: " + count); + + if (!isOpen ()) + throw new ClosedChannelException (); + + if ((mode & READ) == 0) + throw new NonReadableChannelException (); + + final int pageSize = 65536; + long total = 0; + + while (count > 0) + { + int transferred + = smallTransferTo (position, (int)Math.min (count, pageSize), + target); + if (transferred < 0) + break; + total += transferred; + position += transferred; + count -= transferred; + } + + return total; + } + + // like transferFrom, but with a count of less than 2Gbytes + private int smallTransferFrom (ReadableByteChannel src, long position, + int count) + throws IOException + { + ByteBuffer buffer = null; + + if (src instanceof FileChannel) + { + try + { + // Try to use a mapped buffer if we can. If this fails + // for any reason we'll fall back to using a ByteBuffer. + buffer = ((FileChannel)src).map (MapMode.READ_ONLY, position, + count); + } + catch (IOException e) + { + } + } + + if (buffer == null) + { + buffer = ByteBuffer.allocate ((int) count); + src.read (buffer); + buffer.flip(); + } + + return write (buffer, position); + } + + public long transferFrom (ReadableByteChannel src, long position, + long count) + throws IOException + { + if (position < 0 + || count < 0) + throw new IllegalArgumentException ("position: " + position + + ", count: " + count); + + if (!isOpen ()) + throw new ClosedChannelException (); + + if ((mode & WRITE) == 0) + throw new NonWritableChannelException (); + + final int pageSize = 65536; + long total = 0; + + while (count > 0) + { + int transferred = smallTransferFrom (src, position, + (int)Math.min (count, pageSize)); + if (transferred < 0) + break; + total += transferred; + position += transferred; + count -= transferred; + } + + return total; + } + + // Shared sanity checks between lock and tryLock methods. + private void lockCheck(long position, long size, boolean shared) + throws IOException + { + if (position < 0 + || size < 0) + throw new IllegalArgumentException ("position: " + position + + ", size: " + size); + + if (!isOpen ()) + throw new ClosedChannelException(); + + if (shared && ((mode & READ) == 0)) + throw new NonReadableChannelException(); + + if (!shared && ((mode & WRITE) == 0)) + throw new NonWritableChannelException(); + } + + public FileLock tryLock (long position, long size, boolean shared) + throws IOException + { + lockCheck(position, size, shared); + + boolean completed = false; + try + { + begin(); + boolean lockable = ch.lock(position, size, shared, false); + completed = true; + return (lockable + ? new FileLockImpl(this, position, size, shared) + : null); + } + finally + { + end(completed); + } + } + + public FileLock lock (long position, long size, boolean shared) + throws IOException + { + lockCheck(position, size, shared); + + boolean completed = false; + try + { + boolean lockable = ch.lock(position, size, shared, true); + completed = true; + return (lockable + ? new FileLockImpl(this, position, size, shared) + : null); + } + finally + { + end(completed); + } + } + + public long position () + throws IOException + { + if (!isOpen ()) + throw new ClosedChannelException (); + + return implPosition (); + } + + public FileChannel position (long newPosition) + throws IOException + { + if (newPosition < 0) + throw new IllegalArgumentException ("newPosition: " + newPosition); + + if (!isOpen ()) + throw new ClosedChannelException (); + + // FIXME note semantics if seeking beyond eof. + // We should seek lazily - only on a write. + seek (newPosition); + return this; + } + + public FileChannel truncate (long size) + throws IOException + { + if (size < 0) + throw new IllegalArgumentException ("size: " + size); + + if (!isOpen ()) + throw new ClosedChannelException (); + + if ((mode & WRITE) == 0) + throw new NonWritableChannelException (); + + if (size < size ()) + implTruncate (size); + + return this; + } + + public String toString() + { + return (super.toString() + + "[ fd: " + ch.getState() + + "; mode: " + Integer.toOctalString(mode) + + "; " + description + " ]"); + } + + /** + * @return The native file descriptor. + * / + public int getNativeFD() + { + return fd; + }*/ +} Index: gnu/java/nio/FileLockImpl.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/nio/FileLockImpl.java,v retrieving revision 1.10 diff -u -r1.10 FileLockImpl.java --- gnu/java/nio/FileLockImpl.java 31 Jul 2005 16:00:42 -0000 1.10 +++ gnu/java/nio/FileLockImpl.java 17 Sep 2006 06:17:11 -0000 @@ -38,8 +38,6 @@ package gnu.java.nio; -import gnu.java.nio.channels.FileChannelImpl; - import java.io.IOException; import java.nio.channels.FileLock; Index: gnu/java/nio/KqueueSelectionKeyImpl.java =================================================================== RCS file: gnu/java/nio/KqueueSelectionKeyImpl.java diff -N gnu/java/nio/KqueueSelectionKeyImpl.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ gnu/java/nio/KqueueSelectionKeyImpl.java 17 Sep 2006 06:17:12 -0000 @@ -0,0 +1,175 @@ +/* KqueueSelectionKeyImpl.java -- selection key for kqueue/kevent. + 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 java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.SelectableChannel; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; + +/** + * @author Casey Marshall (csm@gnu.org) + */ +public class KqueueSelectionKeyImpl extends SelectionKey +{ + int interestOps; + int readyOps; + ByteBuffer nstate; + boolean valid; + int key; + boolean readEverEnabled = false; + boolean writeEverEnabled = false; + + /** The selector we were created for. */ + private final KqueueSelectorImpl selector; + + /** The channel we are attached to. */ + private final SelectableChannel channel; + + private final VMChannelOwner natChannel; + + public KqueueSelectionKeyImpl(KqueueSelectorImpl selector, + SelectableChannel channel) + { + this.selector = selector; + this.channel = channel; + natChannel = (VMChannelOwner) channel; + interestOps = 0; + readyOps = 0; + valid = true; + } + + /* (non-Javadoc) + * @see java.nio.channels.SelectionKey#cancel() + */ + //@Override + public void cancel() + { + selector.doCancel(this); + valid = false; + } + + /* (non-Javadoc) + * @see java.nio.channels.SelectionKey#channel() + */ + //@Override + public SelectableChannel channel() + { + return channel; + } + + /* (non-Javadoc) + * @see java.nio.channels.SelectionKey#interestOps() + */ + //@Override + public int interestOps() + { + return interestOps; + } + + /* (non-Javadoc) + * @see java.nio.channels.SelectionKey#interestOps(int) + */ + //@Override + public SelectionKey interestOps(int ops) + { + if (!isValid()) + throw new IllegalStateException(); + if ((ops & ~channel.validOps()) != 0) + throw new IllegalArgumentException(); + this.interestOps = ops; + try + { + selector.updateOps(this, + natChannel.getVMChannel().getState().getNativeFD(), + false); + } + catch (IOException ioe) + { + throw new IllegalStateException("channel is invalid"); + } + return this; + } + + /* (non-Javadoc) + * @see java.nio.channels.SelectionKey#isValid() + */ + //@Override + public boolean isValid() + { + return valid && selector.isOpen(); + } + + /* (non-Javadoc) + * @see java.nio.channels.SelectionKey#readyOps() + */ + //@Override + public int readyOps() + { + return readyOps; + } + + /* (non-Javadoc) + * @see java.nio.channels.SelectionKey#selector() + */ + //@Override + public Selector selector() + { + return selector; + } + + public String toString() + { + if (!isValid()) + return super.toString() + " [ <> ]"; + return super.toString() + " [ interest ops: {" + + ((interestOps & OP_ACCEPT) != 0 ? " OP_ACCEPT" : "") + + ((interestOps & OP_CONNECT) != 0 ? " OP_CONNECT" : "") + + ((interestOps & OP_READ) != 0 ? " OP_READ" : "") + + ((interestOps & OP_WRITE) != 0 ? " OP_WRITE" : "") + + " }; ready ops: {" + + ((readyOps & OP_ACCEPT) != 0 ? " OP_ACCEPT" : "") + + ((readyOps & OP_CONNECT) != 0 ? " OP_CONNECT" : "") + + ((readyOps & OP_READ) != 0 ? " OP_READ" : "") + + ((readyOps & OP_WRITE) != 0 ? " OP_WRITE" : "") + + " } ]"; + } +} Index: gnu/java/nio/KqueueSelectorImpl.java =================================================================== RCS file: gnu/java/nio/KqueueSelectorImpl.java diff -N gnu/java/nio/KqueueSelectorImpl.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ gnu/java/nio/KqueueSelectorImpl.java 17 Sep 2006 06:17:12 -0000 @@ -0,0 +1,434 @@ +/* KqueueSelectorImpl.java -- Selector for systems with kqueue event notification. + 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 java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.ClosedSelectorException; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.spi.AbstractSelectableChannel; +import java.nio.channels.spi.AbstractSelector; +import java.nio.channels.spi.SelectorProvider; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + * A {@link Selector} implementation that uses the kqueue + * event notification facility. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class KqueueSelectorImpl extends AbstractSelector +{ + private static final int sizeof_struct_kevent; + + static + { + try + { + System.loadLibrary("javanio"); + } + catch (Exception x) + { + x.printStackTrace(); + } + + if (kqueue_supported ()) + sizeof_struct_kevent = sizeof_struct_kevent(); + else + sizeof_struct_kevent = -1; + } + + /** + * Tell if kqueue-based selectors are supported on this system. + * + * @return True if this system has kqueue support, and support for it was + * compiled in to Classpath. + */ + public static native boolean kqueue_supported(); + + /* Our native file descriptor. */ + private int kq; + + private HashMap/**/ keys; + private HashSet/**/ selected; + private HashSet/**/ cancelled; + private Thread blockedThread; + + public KqueueSelectorImpl(SelectorProvider provider) throws IOException + { + super(provider); + kq = implOpen(); + keys = new HashMap/**/(); + cancelled = new HashSet(); + } + + protected void implCloseSelector() throws IOException + { + implClose(kq); + kq = -1; + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#keys() + */ + public Set keys() + { + if (!isOpen()) + throw new ClosedSelectorException(); + + return new HashSet(keys.values()); + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#select() + */ + public int select() throws IOException + { + return doSelect(-1); + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#select(long) + */ + public int select(long timeout) throws IOException + { + if (timeout == 0) + timeout = -1; + return doSelect(timeout); + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#selectedKeys() + */ + public Set selectedKeys() + { + if (!isOpen()) + throw new ClosedSelectorException(); + + return selected; + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#selectNow() + */ + public int selectNow() throws IOException + { + return doSelect(0); + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#wakeup() + */ + public Selector wakeup() + { + if (blockedThread != null) + blockedThread.interrupt(); + return this; + } + + synchronized int doSelect(long timeout) throws IOException + { + // FIXME -- I'm unclear on how we should synchronize this; and how to + // handle cancelled keys. + for (Iterator it = cancelled.iterator(); it.hasNext(); ) + { + KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) it.next(); + updateOps(key, 0, true); + } + int events_size = 0; + for (Iterator it = keys.values().iterator(); it.hasNext(); ) + { + KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) it.next(); + if ((key.interestOps & SelectionKey.OP_ACCEPT) != 0 + || (key.interestOps & SelectionKey.OP_READ) != 0) + key.readEverEnabled = true; + if ((key.interestOps & SelectionKey.OP_CONNECT) != 0 + || (key.interestOps & SelectionKey.OP_WRITE) != 0) + key.writeEverEnabled = true; + + if (key.readEverEnabled) + events_size += sizeof_struct_kevent; + if (key.writeEverEnabled) + events_size += sizeof_struct_kevent; + } + + // We handle native events a little strangely here; per selection key, + // we allocate enough space for two struct kevents, the first in the + // list will be our EVFILT_READ filter, the second our EVFILT_WRITE + // one. If only one of the two needs enabling, though, we don't want + // to pass the other to kevent, because that would result in spurious + // events. We can break down our handling as follows: + // + // - READ enabled, WRITE never enabled. We pass only the first structure + // to kevent. + // - WRITE enabled, READ never enabled. Likewise, but only pass the + // second structure. + // - READ and WRITE enabled. Pass both. + // - READ enabled, WRITE enabled in the past. Pass both, with the + // first structure's flag set to EV_ADD or EV_ENABLE, and the second + // with EV_DISABLE. It seems OK to keep sending events with the + // EV_DISABLE flag. + // - WRITE enabled, READ enabled in the past. Likewise, but flipped. + // + // We handle these states with the readEverEnabled and writeEverEnabled + // flags of selection keys; they start off as false, and become true + // the first time we select() with READ or WRITE enabled. They never + // become false. + ByteBuffer events = ByteBuffer.allocateDirect(events_size); + + for (Iterator it = keys.entrySet().iterator(); it.hasNext(); ) + { + Map.Entry e = (Map.Entry) it.next(); + KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) e.getValue(); + + if (key.readEverEnabled) + events.put((ByteBuffer) key.nstate.duplicate().limit + (sizeof_struct_kevent)); + if (key.writeEverEnabled) + events.put((ByteBuffer) key.nstate.duplicate().position + (sizeof_struct_kevent).limit(2 * sizeof_struct_kevent)); + } + events.rewind(); + + //System.out.println("dump of keys to select:"); + //dump_selection_keys(events.duplicate()); + + blockedThread = Thread.currentThread(); + if (blockedThread.isInterrupted()) + timeout = 0; + final int n = kevent(kq, events, events_size / sizeof_struct_kevent, + timeout); + Thread.interrupted(); + + //System.out.println("dump of keys selected:"); + //dump_selection_keys((ByteBuffer) events.duplicate().limit(n * sizeof_struct_kevent)); + + selected = new HashSet/**/(n); + int x = 0; + for (int i = 0; i < n; i++) + { + events.position(x).limit(x + sizeof_struct_kevent); + x += sizeof_struct_kevent; + int y = fetch_key(events.slice()); + KqueueSelectionKeyImpl key = + (KqueueSelectionKeyImpl) keys.get(new Integer(y)); + key.readyOps = ready_ops(events.slice(), key.interestOps); + selected.add(key); + } + for (Iterator it = cancelled.iterator(); it.hasNext(); ) + { + KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) it.next(); + keys.remove(new Integer(key.key)); + it.remove(); + } + + return selected.size(); + } + + protected SelectionKey register(AbstractSelectableChannel channel, + int interestOps, + Object attachment) + { + int native_fd = -1; + try + { + if (channel instanceof VMChannelOwner) + native_fd = ((VMChannelOwner) channel).getVMChannel() + .getState().getNativeFD(); + else + throw new IllegalArgumentException("cannot handle channel type " + + channel.getClass().getName()); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("channel is closed or invalid"); + } + + KqueueSelectionKeyImpl result = new KqueueSelectionKeyImpl(this, channel); + result.interestOps = interestOps; + result.attach(attachment); + int k = System.identityHashCode(result); + while (keys.containsKey(new Integer(k))) + k++; + result.key = k; + keys.put(new Integer(k), result); + result.nstate = ByteBuffer.allocateDirect(2 * sizeof_struct_kevent); + updateOps(result, native_fd, false); + return result; + } + + synchronized void updateOps(KqueueSelectionKeyImpl key) + { + updateOps(key, 0, false); + } + + synchronized void updateOps(KqueueSelectionKeyImpl key, int fd, boolean delete) + { + //System.out.println(">> updating kqueue selection key:"); + //dump_selection_keys(key.nstate.duplicate()); + //System.out.println("<<"); + kevent_set(key.nstate, fd, key.interestOps, key.key, delete); + //System.out.println(">> updated kqueue selection key:"); + //dump_selection_keys(key.nstate.duplicate()); + //System.out.println("<<"); + } + + synchronized void doCancel(KqueueSelectionKeyImpl key) + { + cancelled.add(key); + } + + private void dump_selection_keys(ByteBuffer keys) + { + // WARNING! This method is not guaranteed to be portable! This works + // on darwin/x86, but the sizeof and offsetof these fields may be + // different on other platforms! + int i = 0; + keys.order(ByteOrder.nativeOrder()); + while (keys.hasRemaining()) + { + System.out.println("struct kevent { ident: " + + Integer.toString(keys.getInt()) + + " filter: " + + Integer.toHexString(keys.getShort() & 0xFFFF) + + " flags: " + + Integer.toHexString(keys.getShort() & 0xFFFF) + + " fflags: " + + Integer.toHexString(keys.getInt()) + + " data: " + + Integer.toHexString(keys.getInt()) + + " udata: " + + Integer.toHexString(keys.getInt()) + + " }"); + } + } + + /** + * Return the size of a struct kevent on this system. + * + * @return The size of struct kevent. + */ + private static native int sizeof_struct_kevent(); + + /** + * Opens a kqueue descriptor. + * + * @return The new kqueue descriptor. + * @throws IOException If opening fails. + */ + private static native int implOpen() throws IOException; + + /** + * Closes the kqueue file descriptor. + * + * @param kq The kqueue file descriptor. + * @throws IOException + */ + private static native void implClose(int kq) throws IOException; + + /** + * Initialize the specified native state for the given interest ops. + * + * @param nstate The native state structures; in this buffer should be + * the struct kevents created for a key. + * @param fd The file descriptor. If 0, the native FD is unmodified. + * @param interestOps The operations to enable. + * @param key A unique key that will reference the associated key later. + * @param delete Set to true if this event should be deleted from the + * kqueue (if false, this event is added/updated). + */ + private static native void kevent_set(ByteBuffer nstate, int fd, int interestOps, + int key, boolean delete); + + /** + * Poll for events. The source events are stored in events, + * which is also where polled events will be placed. + * + * @param events The events to poll. This buffer is also the destination + * for events read from the queue. + * @param nevents The number of events to poll (that is, the number of + * events in the events buffer). + * @param timeout The timeout. A timeout of -1 returns immediately; a timeout + * of 0 waits indefinitely. + * @return The number of events read. + */ + private static native int kevent(int kq, ByteBuffer events, int nevents, + long timeout); + + /** + * Fetch a polled key from a native state buffer. For each kevent key we + * create, we put the native state info (one or more struct + * kevents) in that key's {@link KqueueSelectionKeyImpl#nstate} + * buffer, and place the pointer of the key in the udata field + * of that structure. This method fetches that pointer from the given + * buffer (assumed to be a struct kqueue) and returns it. + * + * @param nstate The buffer containing the struct kqueue to read. + * @return The key object. + */ + private static native int fetch_key(ByteBuffer nstate); + + /** + * Fetch the ready ops of the associated native state. That is, this + * inspects the first argument as a struct kevent, looking + * at its operation (the input is assumed to have been returned via a + * previous call to kevent), and translating that to the + * appropriate Java bit set, based on the second argument. + * + * @param nstate The native state. + * @param interestOps The enabled operations for the key. + * @return The bit set representing the ready operations. + */ + private static native int ready_ops(ByteBuffer nstate, int interestOps); + + /** + * Check if kevent returned EV_EOF for a selection key. + * + * @param nstate The native state. + * @return True if the kevent call returned EOF. + */ + private static native boolean check_eof(ByteBuffer nstate); +} Index: gnu/java/nio/NIOSocket.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/nio/NIOSocket.java,v retrieving revision 1.4 diff -u -r1.4 NIOSocket.java --- gnu/java/nio/NIOSocket.java 2 Jul 2005 20:32:13 -0000 1.4 +++ gnu/java/nio/NIOSocket.java 17 Sep 2006 06:17:12 -0000 @@ -48,30 +48,33 @@ */ public final class NIOSocket extends Socket { - private PlainSocketImpl impl; private SocketChannelImpl channel; - protected NIOSocket (PlainSocketImpl impl, SocketChannelImpl channel) + protected NIOSocket (SocketChannelImpl channel) throws IOException { - super (impl); - this.impl = impl; + super (new NIOSocketImpl(channel)); this.channel = channel; } - public final PlainSocketImpl getPlainSocketImpl() - { - return impl; - } + //public final PlainSocketImpl getPlainSocketImpl() + //{ + // return impl; + //} - final void setChannel (SocketChannelImpl channel) - { - this.impl = channel.getPlainSocketImpl(); - this.channel = channel; - } + //final void setChannel (SocketChannelImpl channel) + //{ + // this.impl = channel.getPlainSocketImpl(); + // this.channel = channel; + //} public final SocketChannel getChannel() { return channel; } + + public boolean isConnected() + { + return channel.isConnected(); + } } Index: gnu/java/nio/NIOSocketImpl.java =================================================================== RCS file: gnu/java/nio/NIOSocketImpl.java diff -N gnu/java/nio/NIOSocketImpl.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ gnu/java/nio/NIOSocketImpl.java 17 Sep 2006 06:17:12 -0000 @@ -0,0 +1,110 @@ +/* NIOSocketImpl.java -- subclass of PlainSocketImpl for NIO. + 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.java.net.PlainSocketImpl; + +import java.io.IOException; +import java.net.InetAddress; + +/** + * @author Casey Marshall (csm@gnu.org) + */ +public class NIOSocketImpl extends PlainSocketImpl +{ + + private final SocketChannelImpl channel; + + NIOSocketImpl(SocketChannelImpl channel) throws IOException + { + this.channel = channel; + impl.getState().setChannelFD(channel.getVMChannel().getState()); + } + + /* (non-Javadoc) + * @see java.net.SocketImpl#getInetAddress() + */ + //@Override + protected InetAddress getInetAddress() + { + try + { + return channel.getVMChannel().getPeerAddress().getAddress(); + } + catch (IOException ioe) + { + return null; + } + catch (NullPointerException npe) + { + // Socket is not connected yet. + return null; + } + } + + /* (non-Javadoc) + * @see java.net.SocketImpl#getPort() + */ + //@Override + protected int getPort() + { + try + { + return channel.getVMChannel().getPeerAddress().getPort(); + } + catch (IOException ioe) + { + return -1; + } + catch (NullPointerException npe) + { + // Socket is not connected yet. + return -1; + } + } + + /* (non-Javadoc) + * @see gnu.java.net.PlainSocketImpl#create(boolean) + */ + //@Override + protected synchronized void create(boolean stream) + { + // Ignored; the socket has already been created. + } +} Index: gnu/java/nio/PipeImpl.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/nio/PipeImpl.java,v retrieving revision 1.12 diff -u -r1.12 PipeImpl.java --- gnu/java/nio/PipeImpl.java 14 May 2006 03:34:54 -0000 1.12 +++ gnu/java/nio/PipeImpl.java 17 Sep 2006 06:17:12 -0000 @@ -46,22 +46,21 @@ class PipeImpl extends Pipe { public static final class SourceChannelImpl extends Pipe.SourceChannel + implements VMChannelOwner { - private int native_fd; private VMChannel vmch; public SourceChannelImpl (SelectorProvider selectorProvider, - int native_fd) + VMChannel channel) { super (selectorProvider); - this.native_fd = native_fd; - vmch = VMChannel.getVMChannel(this); + vmch = channel; } protected final void implCloseSelectableChannel() throws IOException { - throw new Error ("Not implemented"); + vmch.close(); } protected void implConfigureBlocking (boolean blocking) @@ -94,30 +93,29 @@ return vmch.readScattering(srcs, offset, len); } - - public final int getNativeFD() + + public VMChannel getVMChannel() { - return native_fd; + return vmch; } } public static final class SinkChannelImpl extends Pipe.SinkChannel + implements VMChannelOwner { - private int native_fd; private VMChannel vmch; public SinkChannelImpl (SelectorProvider selectorProvider, - int native_fd) + VMChannel channel) { super (selectorProvider); - this.native_fd = native_fd; - vmch = VMChannel.getVMChannel(this); + vmch = channel; } protected final void implCloseSelectableChannel() throws IOException { - throw new Error ("Not implemented"); + vmch.close(); } protected final void implConfigureBlocking (boolean blocking) @@ -149,10 +147,10 @@ return vmch.writeGathering(srcs, offset, len); } - - public final int getNativeFD() + + public VMChannel getVMChannel() { - return native_fd; + return vmch; } } @@ -163,7 +161,9 @@ throws IOException { super(); - VMPipe.init (this, provider); + VMChannel[] pipe = VMPipe.pipe(); + sink = new SinkChannelImpl(provider, pipe[0]); + source = new SourceChannelImpl(provider, pipe[1]); } public Pipe.SinkChannel sink() Index: gnu/java/nio/SelectionKeyImpl.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/nio/SelectionKeyImpl.java,v retrieving revision 1.10 diff -u -r1.10 SelectionKeyImpl.java --- gnu/java/nio/SelectionKeyImpl.java 31 Jul 2006 22:08:00 -0000 1.10 +++ gnu/java/nio/SelectionKeyImpl.java 17 Sep 2006 06:17:12 -0000 @@ -106,5 +106,6 @@ return impl; } + /* @deprecated */ public abstract int getNativeFD(); } 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 17 Sep 2006 06:17:12 -0000 @@ -37,6 +37,9 @@ package gnu.java.nio; + +import gnu.classpath.SystemProperties; + import java.io.IOException; import java.nio.channels.DatagramChannel; import java.nio.channels.Pipe; @@ -47,6 +50,10 @@ public class SelectorProviderImpl extends SelectorProvider { + private static final String SELECTOR_IMPL_KQUEUE = "kqueue"; + private static final String SELECTOR_IMPL_EPOLL = "epoll"; + private static final String SELECTOR_IMPL = "gnu.java.nio.selectorImpl"; + public SelectorProviderImpl () { } @@ -66,6 +73,16 @@ public AbstractSelector openSelector () throws IOException { + String selectorImpl = "default"; + if (KqueueSelectorImpl.kqueue_supported()) + selectorImpl = SELECTOR_IMPL_KQUEUE; + selectorImpl = SystemProperties.getProperty(SELECTOR_IMPL, selectorImpl); + + if (selectorImpl.equals(SELECTOR_IMPL_KQUEUE)) + return new KqueueSelectorImpl(this); + if (selectorImpl.equals(SELECTOR_IMPL_EPOLL)) + throw new UnsupportedOperationException("epoll selector not yet implemented"); + return new SelectorImpl (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 17 Sep 2006 06:17:12 -0000 @@ -48,7 +48,9 @@ import java.nio.channels.spi.SelectorProvider; public final class ServerSocketChannelImpl extends ServerSocketChannel + implements VMChannelOwner { + private VMChannel channel; private NIOServerSocket serverSocket; private boolean connected; @@ -56,13 +58,15 @@ throws IOException { super (provider); - serverSocket = new NIOServerSocket (this); + serverSocket = new NIOServerSocket(this); + channel = serverSocket.getPlainSocketImpl().getVMChannel(); configureBlocking(true); } + // XXX do we need this? public void finalizer() { - if (connected) + if (channel.getState().isValid()) { try { @@ -77,12 +81,12 @@ protected void implCloseSelectableChannel () throws IOException { connected = false; - serverSocket.close(); + channel.close(); } protected void implConfigureBlocking (boolean blocking) throws IOException { - serverSocket.setSoTimeout (blocking ? 0 : NIOConstants.DEFAULT_TIMEOUT); + channel.setBlocking(blocking); } public SocketChannel accept () throws IOException @@ -98,27 +102,28 @@ try { begin(); - serverSocket.getPlainSocketImpl().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. - NIOSocket socket = (NIOSocket) serverSocket.accept(); - completed = true; - return socket.getChannel(); - } - catch (SocketTimeoutException e) - { - return null; + VMChannel client = channel.accept(); + if (client == null) + return null; + else + { + completed = true; + return new SocketChannelImpl(provider(), client, false); + } } finally { - serverSocket.getPlainSocketImpl().setInChannelOperation(false); end (completed); } } - public ServerSocket socket () + public ServerSocket socket() { return serverSocket; } + + public VMChannel getVMChannel() + { + return channel; + } } Index: gnu/java/nio/ServerSocketChannelSelectionKey.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/nio/ServerSocketChannelSelectionKey.java,v retrieving revision 1.3 diff -u -r1.3 ServerSocketChannelSelectionKey.java --- gnu/java/nio/ServerSocketChannelSelectionKey.java 2 Jul 2005 20:32:13 -0000 1.3 +++ gnu/java/nio/ServerSocketChannelSelectionKey.java 17 Sep 2006 06:17:12 -0000 @@ -38,6 +38,7 @@ package gnu.java.nio; +import java.io.IOException; import java.nio.channels.spi.AbstractSelectableChannel; public final class ServerSocketChannelSelectionKey @@ -49,10 +50,16 @@ super (channel, selector); } + // FIXME don't use file descriptor integers public int getNativeFD() { - NIOServerSocket socket = - (NIOServerSocket) ((ServerSocketChannelImpl) ch).socket(); - return socket.getPlainSocketImpl().getNativeFD(); + try + { + return ((ServerSocketChannelImpl) ch).getVMChannel().getState().getNativeFD(); + } + catch (IOException ioe) + { + throw new IllegalStateException(ioe); + } } } 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 17 Sep 2006 06:17:12 -0000 @@ -39,15 +39,20 @@ package gnu.java.nio; import gnu.java.net.PlainSocketImpl; +import gnu.java.net.VMPlainSocketImpl; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketAddress; +import java.net.SocketException; import java.net.SocketTimeoutException; import java.nio.ByteBuffer; +import java.nio.ReadOnlyBufferException; import java.nio.channels.AlreadyConnectedException; import java.nio.channels.ClosedChannelException; import java.nio.channels.ConnectionPendingException; @@ -61,28 +66,57 @@ import java.nio.channels.spi.SelectorProvider; public final class SocketChannelImpl extends SocketChannel + implements VMChannelOwner { - private PlainSocketImpl impl; + private VMChannel channel; + //private PlainSocketImpl impl; private NIOSocket socket; private boolean connectionPending; + private boolean connected; + private InetSocketAddress connectAddress; + + public SocketChannelImpl(boolean create) throws IOException + { + // XXX consider adding security check; this is used by + // PlainSocketImpl. + this(new SelectorProviderImpl(), create); + } + + public SocketChannelImpl(VMChannel channel) throws IOException + { + this(new SelectorProviderImpl(), channel, false); + } + + SocketChannelImpl(SelectorProvider provider) throws IOException + { + this(provider, true); + } - SocketChannelImpl (SelectorProvider provider) + SocketChannelImpl(SelectorProvider provider, boolean create) + throws IOException + { + this(provider, new VMChannel(), create); + } + + SocketChannelImpl(SelectorProvider provider, VMChannel channel, boolean create) throws IOException { super (provider); - impl = new PlainSocketImpl(); - socket = new NIOSocket (impl, this); + this.channel = channel; + if (create) + channel.initSocket(true); + socket = new NIOSocket(this); configureBlocking(true); } - SocketChannelImpl (SelectorProvider provider, + /*SocketChannelImpl (SelectorProvider provider, NIOSocket socket) throws IOException { super (provider); this.impl = socket.getPlainSocketImpl(); this.socket = socket; - } + }*/ public void finalizer() { @@ -98,23 +132,28 @@ } } - PlainSocketImpl getPlainSocketImpl() - { - return impl; - } + //PlainSocketImpl getPlainSocketImpl() + //{ + // return null; // XXX + //} - protected void implCloseSelectableChannel () throws IOException + protected void implCloseSelectableChannel() throws IOException { - socket.close(); + channel.close(); } protected void implConfigureBlocking (boolean blocking) throws IOException { - socket.setSoTimeout (blocking ? 0 : NIOConstants.DEFAULT_TIMEOUT); + channel.setBlocking(blocking); } public boolean connect (SocketAddress remote) throws IOException { + return connect(remote, 0); + } + + public boolean connect (SocketAddress remote, int timeout) throws IOException + { if (!isOpen()) throw new ClosedChannelException(); @@ -126,40 +165,15 @@ if (!(remote instanceof InetSocketAddress)) throw new UnsupportedAddressTypeException(); + + connectAddress = (InetSocketAddress) remote; - if (((InetSocketAddress) remote).isUnresolved()) + if (connectAddress.isUnresolved()) throw new UnresolvedAddressException(); - try - { - socket.getPlainSocketImpl().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 - { - socket.getPlainSocketImpl().setInChannelOperation(false); - } + connected = channel.connect(connectAddress, timeout); + connectionPending = !connected; + return connected; } public boolean finishConnect () @@ -168,37 +182,30 @@ 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; - } - + + if (!connectionPending) + throw new NoConnectionPendingException(); + return false; } - public boolean isConnected () + public boolean isConnected() { - return socket.isConnected(); + try + { + InetSocketAddress remote = channel.getPeerAddress(); + return remote != null; + } + catch (IOException ioe) + { + ioe.printStackTrace(System.out); + return false; + } } public boolean isConnectionPending () @@ -216,52 +223,7 @@ 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; - - try - { - begin(); - socket.getPlainSocketImpl().setInChannelOperation(true); - readBytes = input.read (data, offset, len); - completed = true; - } - finally - { - end (completed); - socket.getPlainSocketImpl().setInChannelOperation(false); - } - - if (readBytes > 0) - if (dst.hasArray()) - { - dst.position (dst.position() + readBytes); - } - else - { - dst.put (data, offset, readBytes); - } - - return readBytes; + return channel.read(dst); } public long read (ByteBuffer[] dsts, int offset, int length) @@ -275,61 +237,19 @@ || (length < 0) || (length > (dsts.length - offset))) throw new IndexOutOfBoundsException(); - - long readBytes = 0; - - for (int index = offset; index < length; index++) - readBytes += read (dsts [index]); - - return readBytes; + + return channel.readScattering(dsts, offset, length); } - public int write (ByteBuffer src) - throws IOException + public int write(ByteBuffer src) throws IOException { 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(); - boolean completed = false; - - try - { - begin(); - socket.getPlainSocketImpl().setInChannelOperation(true); - output.write (data, offset, len); - completed = true; - } - finally - { - end (completed); - socket.getPlainSocketImpl().setInChannelOperation(false); - } - if (src.hasArray()) - { - src.position (src.position() + len); - } - - return len; + return channel.write(src); } - public long write (ByteBuffer[] srcs, int offset, int length) + public long write(ByteBuffer[] srcs, int offset, int length) throws IOException { if (!isConnected()) @@ -340,12 +260,13 @@ || (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; + return channel.writeGathering(srcs, offset, length); + } + + public VMChannel getVMChannel() + { + // XXX security check? + return channel; } } Index: gnu/java/nio/SocketChannelSelectionKey.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/nio/SocketChannelSelectionKey.java,v retrieving revision 1.3 diff -u -r1.3 SocketChannelSelectionKey.java --- gnu/java/nio/SocketChannelSelectionKey.java 2 Jul 2005 20:32:13 -0000 1.3 +++ gnu/java/nio/SocketChannelSelectionKey.java 17 Sep 2006 06:17:12 -0000 @@ -38,6 +38,7 @@ package gnu.java.nio; +import java.io.IOException; import java.nio.channels.spi.AbstractSelectableChannel; public final class SocketChannelSelectionKey @@ -49,10 +50,16 @@ super (channel, selector); } + // FIXME don't use file descriptor integers public int getNativeFD() { - NIOSocket socket = - (NIOSocket) ((SocketChannelImpl) ch).socket(); - return socket.getPlainSocketImpl().getNativeFD(); + try + { + return ((SocketChannelImpl) ch).getVMChannel().getState().getNativeFD(); + } + catch (IOException ioe) + { + throw new IllegalStateException(ioe); + } } } Index: gnu/java/nio/SocketChannelSelectionKeyImpl.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/nio/SocketChannelSelectionKeyImpl.java,v retrieving revision 1.1 diff -u -r1.1 SocketChannelSelectionKeyImpl.java --- gnu/java/nio/SocketChannelSelectionKeyImpl.java 14 May 2006 03:34:54 -0000 1.1 +++ gnu/java/nio/SocketChannelSelectionKeyImpl.java 17 Sep 2006 06:17:12 -0000 @@ -38,6 +38,8 @@ package gnu.java.nio; +import java.io.IOException; + /** * @author Michael Barker @@ -63,7 +65,14 @@ */ public int getNativeFD() { - return ch.getPlainSocketImpl().getNativeFD(); + try + { + return ch.getVMChannel().getState().getNativeFD(); + } + catch (IOException ioe) + { + return 0; // FIXME + } } } Index: gnu/java/nio/VMChannelOwner.java =================================================================== RCS file: gnu/java/nio/VMChannelOwner.java diff -N gnu/java/nio/VMChannelOwner.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ gnu/java/nio/VMChannelOwner.java 17 Sep 2006 06:17:12 -0000 @@ -0,0 +1,60 @@ +/* NativeFD.java -- interface for Channels that have an underlying file descriptor. + 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 java.nio.channels.Channel; +import java.nio.channels.Selector; + +/** + * This interface is meant to be implemented by any {@link Channel} + * implementation we support that uses a platform-specific {@link VMChannel} + * at their core. This is primarily used by {@link Selector} implementations, + * for easier access to the native state. + * + * @author Casey Marshall (csm@gnu.org) + */ +interface VMChannelOwner +{ + /** + * Return the underlying platform-specific Channel instance. + * + * @return The platform channel object. + */ + VMChannel getVMChannel(); +} Index: gnu/java/nio/channels/FileChannelImpl.java =================================================================== RCS file: gnu/java/nio/channels/FileChannelImpl.java diff -N gnu/java/nio/channels/FileChannelImpl.java --- gnu/java/nio/channels/FileChannelImpl.java 14 May 2006 03:34:55 -0000 1.22 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,553 +0,0 @@ -/* FileChannelImpl.java -- - Copyright (C) 2002, 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. */ - - -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; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.MappedByteBuffer; -import java.nio.channels.ClosedChannelException; -import java.nio.channels.FileChannel; -import java.nio.channels.FileLock; -import java.nio.channels.NonReadableChannelException; -import java.nio.channels.NonWritableChannelException; -import java.nio.channels.ReadableByteChannel; -import java.nio.channels.WritableByteChannel; - -/** - * This file is not user visible ! - * But alas, Java does not have a concept of friendly packages - * so this class is public. - * Instances of this class are created by invoking getChannel - * Upon a Input/Output/RandomAccessFile object. - */ -public final class FileChannelImpl extends FileChannel -{ - // These are mode values for open(). - public static final int READ = 1; - public static final int WRITE = 2; - public static final int APPEND = 4; - - // EXCL is used only when making a temp file. - public static final int EXCL = 8; - public static final int SYNC = 16; - public static final int DSYNC = 32; - - public static FileChannelImpl in; - public static FileChannelImpl out; - public static FileChannelImpl err; - - private static native void init(); - - static - { - if (Configuration.INIT_LOAD_LIBRARY) - { - System.loadLibrary("javanio"); - } - - init(); - - in = new FileChannelImpl(0, READ); - out = new FileChannelImpl(1, WRITE); - err = new FileChannelImpl(2, WRITE); - } - - /** - * This is the actual native file descriptor value - */ - // System's notion of file descriptor. It might seem redundant to - // initialize this given that it is reassigned in the constructors. - // However, this is necessary because if open() throws an exception - // 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; - - final String description; - - /* Open a file. MODE is a combination of the above mode flags. */ - /* This is a static factory method, so that VM implementors can decide - * substitute subclasses of FileChannelImpl. */ - public static FileChannelImpl create(File file, int mode) - throws FileNotFoundException - { - return new FileChannelImpl(file, mode); - } - - private FileChannelImpl(File file, int mode) - throws FileNotFoundException - { - String path = file.getPath(); - 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. - if (file.isDirectory()) - { - try - { - close(); - } - catch (IOException e) - { - /* ignore it */ - } - - throw new FileNotFoundException(description + " is a directory"); - } - } - - /** - * Constructor for default channels in, out and err. - * - * Used by init() (native code). - * - * @param fd the file descriptor (0, 1, 2 for stdin, stdout, stderr). - * - * @param mode READ or WRITE - */ - FileChannelImpl (int fd, int mode) - { - 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; - - public native int available () throws IOException; - private native long implPosition () throws IOException; - private native void seek (long newPosition) throws IOException; - private native void implTruncate (long size) throws IOException; - - public native void unlock (long pos, long len) throws IOException; - - public native long size () throws IOException; - - protected native void implCloseChannel() throws IOException; - - /** - * Makes sure the Channel is properly closed. - */ - protected void finalize() throws IOException - { - if (fd != -1) - close(); - } - - public int read (ByteBuffer dst) throws IOException - { - /* - int result; - byte[] buffer = new byte [dst.remaining ()]; - - result = read (buffer, 0, buffer.length); - - if (result > 0) - dst.put (buffer, 0, result); - - return result; - */ - return ch.read(dst); - } - - public int read (ByteBuffer dst, long position) - throws IOException - { - if (position < 0) - throw new IllegalArgumentException ("position: " + position); - long oldPosition = implPosition (); - position (position); - int result = read(dst); - position (oldPosition); - - return result; - } - - public native int read () - throws IOException; - - public native int read (byte[] buffer, int offset, int length) - throws IOException; - - public long read (ByteBuffer[] dsts, int offset, int length) - throws IOException - { - return ch.readScattering(dsts, offset, length); - } - - public int write (ByteBuffer src) throws IOException - { - return ch.write(src); - } - - public int write (ByteBuffer src, long position) - throws IOException - { - if (position < 0) - throw new IllegalArgumentException ("position: " + position); - - if (!isOpen ()) - throw new ClosedChannelException (); - - if ((mode & WRITE) == 0) - throw new NonWritableChannelException (); - - int result; - long oldPosition; - - oldPosition = implPosition (); - seek (position); - result = write(src); - seek (oldPosition); - - return result; - } - - public native void write (byte[] buffer, int offset, int length) - throws IOException; - - public native void write (int b) throws IOException; - - public long write(ByteBuffer[] srcs, int offset, int length) - throws IOException - { - return ch.writeGathering(srcs, offset, length); - } - - public native MappedByteBuffer mapImpl (char mode, long position, int size) - throws IOException; - - public MappedByteBuffer map (FileChannel.MapMode mode, - long position, long size) - throws IOException - { - char nmode = 0; - if (mode == MapMode.READ_ONLY) - { - nmode = 'r'; - if ((this.mode & READ) == 0) - throw new NonReadableChannelException(); - } - else if (mode == MapMode.READ_WRITE || mode == MapMode.PRIVATE) - { - nmode = mode == MapMode.READ_WRITE ? '+' : 'c'; - if ((this.mode & WRITE) != WRITE) - throw new NonWritableChannelException(); - if ((this.mode & READ) != READ) - throw new NonReadableChannelException(); - } - else - throw new IllegalArgumentException ("mode: " + mode); - - if (position < 0 || size < 0 || size > Integer.MAX_VALUE) - throw new IllegalArgumentException ("position: " + position - + ", size: " + size); - return mapImpl(nmode, position, (int) size); - } - - /** - * msync with the disk - */ - public void force (boolean metaData) throws IOException - { - if (!isOpen ()) - throw new ClosedChannelException (); - - force (); - } - - private native void force (); - - // like transferTo, but with a count of less than 2Gbytes - private int smallTransferTo (long position, int count, - WritableByteChannel target) - throws IOException - { - ByteBuffer buffer; - try - { - // Try to use a mapped buffer if we can. If this fails for - // any reason we'll fall back to using a ByteBuffer. - buffer = map (MapMode.READ_ONLY, position, count); - } - catch (IOException e) - { - buffer = ByteBuffer.allocate (count); - read (buffer, position); - buffer.flip(); - } - - return target.write (buffer); - } - - public long transferTo (long position, long count, - WritableByteChannel target) - throws IOException - { - if (position < 0 - || count < 0) - throw new IllegalArgumentException ("position: " + position - + ", count: " + count); - - if (!isOpen ()) - throw new ClosedChannelException (); - - if ((mode & READ) == 0) - throw new NonReadableChannelException (); - - final int pageSize = 65536; - long total = 0; - - while (count > 0) - { - int transferred - = smallTransferTo (position, (int)Math.min (count, pageSize), - target); - if (transferred < 0) - break; - total += transferred; - position += transferred; - count -= transferred; - } - - return total; - } - - // like transferFrom, but with a count of less than 2Gbytes - private int smallTransferFrom (ReadableByteChannel src, long position, - int count) - throws IOException - { - ByteBuffer buffer = null; - - if (src instanceof FileChannel) - { - try - { - // Try to use a mapped buffer if we can. If this fails - // for any reason we'll fall back to using a ByteBuffer. - buffer = ((FileChannel)src).map (MapMode.READ_ONLY, position, - count); - } - catch (IOException e) - { - } - } - - if (buffer == null) - { - buffer = ByteBuffer.allocate ((int) count); - src.read (buffer); - buffer.flip(); - } - - return write (buffer, position); - } - - public long transferFrom (ReadableByteChannel src, long position, - long count) - throws IOException - { - if (position < 0 - || count < 0) - throw new IllegalArgumentException ("position: " + position - + ", count: " + count); - - if (!isOpen ()) - throw new ClosedChannelException (); - - if ((mode & WRITE) == 0) - throw new NonWritableChannelException (); - - final int pageSize = 65536; - long total = 0; - - while (count > 0) - { - int transferred = smallTransferFrom (src, position, - (int)Math.min (count, pageSize)); - if (transferred < 0) - break; - total += transferred; - position += transferred; - count -= transferred; - } - - return total; - } - - // Shared sanity checks between lock and tryLock methods. - private void lockCheck(long position, long size, boolean shared) - throws IOException - { - if (position < 0 - || size < 0) - throw new IllegalArgumentException ("position: " + position - + ", size: " + size); - - if (!isOpen ()) - throw new ClosedChannelException(); - - if (shared && ((mode & READ) == 0)) - throw new NonReadableChannelException(); - - if (!shared && ((mode & WRITE) == 0)) - throw new NonWritableChannelException(); - } - - public FileLock tryLock (long position, long size, boolean shared) - throws IOException - { - lockCheck(position, size, shared); - - boolean completed = false; - try - { - begin(); - boolean lockable = lock(position, size, shared, false); - completed = true; - return (lockable - ? new FileLockImpl(this, position, size, shared) - : null); - } - finally - { - end(completed); - } - } - - /** Try to acquire a lock at the given position and size. - * On success return true. - * If wait as specified, block until we can get it. - * Otherwise return false. - */ - private native boolean lock(long position, long size, - boolean shared, boolean wait) throws IOException; - - public FileLock lock (long position, long size, boolean shared) - throws IOException - { - lockCheck(position, size, shared); - - boolean completed = false; - try - { - boolean lockable = lock(position, size, shared, true); - completed = true; - return (lockable - ? new FileLockImpl(this, position, size, shared) - : null); - } - finally - { - end(completed); - } - } - - public long position () - throws IOException - { - if (!isOpen ()) - throw new ClosedChannelException (); - - return implPosition (); - } - - public FileChannel position (long newPosition) - throws IOException - { - if (newPosition < 0) - throw new IllegalArgumentException ("newPosition: " + newPosition); - - if (!isOpen ()) - throw new ClosedChannelException (); - - // FIXME note semantics if seeking beyond eof. - // We should seek lazily - only on a write. - seek (newPosition); - return this; - } - - public FileChannel truncate (long size) - throws IOException - { - if (size < 0) - throw new IllegalArgumentException ("size: " + size); - - if (!isOpen ()) - throw new ClosedChannelException (); - - if ((mode & WRITE) == 0) - throw new NonWritableChannelException (); - - if (size < size ()) - implTruncate (size); - - return this; - } - - public String toString() - { - return (this.getClass() - + "[fd=" + fd - + ",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.69 diff -u -r1.69 Makefile.am --- include/Makefile.am 17 Jul 2006 18:37:19 -0000 1.69 +++ include/Makefile.am 17 Sep 2006 06:17:12 -0000 @@ -128,10 +128,11 @@ $(top_srcdir)/include/gnu_java_net_VMPlainDatagramSocketImpl.h \ $(top_srcdir)/include/gnu_java_net_VMPlainSocketImpl.h \ $(top_srcdir)/include/gnu_java_net_local_LocalSocketImpl.h \ +$(top_srcdir)/include/gnu_java_nio_FileChannelImpl.h \ +$(top_srcdir)/include/gnu_java_nio_KqueueSelectorImpl.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 \ $(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 \ @@ -214,12 +215,18 @@ $(JAVAH) -o $@ java.net.VMNetworkInterface $(top_srcdir)/include/java_net_VMURLConnection.h: $(top_srcdir)/vm/reference/java/net/VMURLConnection.java $(JAVAH) -o $@ java.net.VMURLConnection + $(top_srcdir)/include/java_nio_VMDirectByteBuffer.h: $(top_srcdir)/vm/reference/java/nio/VMDirectByteBuffer.java $(JAVAH) -o $@ java.nio.VMDirectByteBuffer $(top_srcdir)/include/java_nio_MappedByteBufferImpl.h: $(top_srcdir)/java/nio/MappedByteBufferImpl.java $(JAVAH) -o $@ java.nio.MappedByteBufferImpl -$(top_srcdir)/include/gnu_java_nio_channels_FileChannelImpl.h: $(top_srcdir)/gnu/java/nio/channels/FileChannelImpl.java - $(