changeset 5386:75f67d481b91

7172826: (se) Selector based on the Solaris event port mechanism Reviewed-by: alanb
author robm
date Tue, 23 Oct 2012 03:00:10 +0100
parents 2b035ad28fbf
children 3ba27e5ab1f9
files make/java/nio/Makefile make/java/nio/mapfile-linux make/java/nio/mapfile-solaris src/share/classes/sun/nio/ch/IOUtil.java src/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java src/solaris/classes/sun/nio/ch/EventPortSelectorImpl.java src/solaris/classes/sun/nio/ch/EventPortSelectorProvider.java src/solaris/classes/sun/nio/ch/EventPortWrapper.java src/solaris/classes/sun/nio/ch/SolarisEventPort.java src/solaris/native/sun/nio/ch/DevPollArrayWrapper.c src/solaris/native/sun/nio/ch/EPollArrayWrapper.c src/solaris/native/sun/nio/ch/IOUtil.c src/solaris/native/sun/nio/ch/SolarisEventPort.c test/java/nio/channels/Selector/lots_of_updates.sh test/java/nio/channels/SocketChannel/Open.sh test/sun/nio/ch/SelProvider.java
diffstat 17 files changed, 617 insertions(+), 113 deletions(-) [+]
line wrap: on
line diff
--- a/make/java/nio/Makefile	Tue Sep 18 11:04:12 2012 -0700
+++ b/make/java/nio/Makefile	Tue Oct 23 03:00:10 2012 +0100
@@ -54,6 +54,9 @@
 	sun/nio/ch/DevPollArrayWrapper.java \
 	sun/nio/ch/DevPollSelectorImpl.java \
         sun/nio/ch/DevPollSelectorProvider.java \
+	sun/nio/ch/EventPortSelectorImpl.java \
+	sun/nio/ch/EventPortSelectorProvider.java \
+	sun/nio/ch/EventPortWrapper.java \
 	sun/nio/ch/InheritedChannel.java \
         sun/nio/ch/PollSelectorProvider.java \
         sun/nio/ch/PollSelectorImpl.java \
--- a/make/java/nio/mapfile-linux	Tue Sep 18 11:04:12 2012 -0700
+++ b/make/java/nio/mapfile-linux	Tue Oct 23 03:00:10 2012 +0100
@@ -39,7 +39,6 @@
                 Java_sun_nio_ch_EPollArrayWrapper_epollCreate;
                 Java_sun_nio_ch_EPollArrayWrapper_epollCtl;
                 Java_sun_nio_ch_EPollArrayWrapper_epollWait;
-		Java_sun_nio_ch_EPollArrayWrapper_fdLimit;
 		Java_sun_nio_ch_EPollArrayWrapper_init;
 		Java_sun_nio_ch_EPollArrayWrapper_interrupt;
 		Java_sun_nio_ch_EPollArrayWrapper_offsetofData;
@@ -87,6 +86,7 @@
                 Java_sun_nio_ch_IOUtil_configureBlocking;
                 Java_sun_nio_ch_IOUtil_drain;
                 Java_sun_nio_ch_IOUtil_fdVal;
+		Java_sun_nio_ch_IOUtil_fdLimit;
                 Java_sun_nio_ch_IOUtil_initIDs;
 		Java_sun_nio_ch_IOUtil_iovMax;
                 Java_sun_nio_ch_IOUtil_makePipe;
--- a/make/java/nio/mapfile-solaris	Tue Sep 18 11:04:12 2012 -0700
+++ b/make/java/nio/mapfile-solaris	Tue Oct 23 03:00:10 2012 +0100
@@ -36,7 +36,6 @@
                 Java_sun_nio_ch_DatagramDispatcher_readv0;
                 Java_sun_nio_ch_DatagramDispatcher_write0;
                 Java_sun_nio_ch_DatagramDispatcher_writev0;
-                Java_sun_nio_ch_DevPollArrayWrapper_fdLimit;
                 Java_sun_nio_ch_DevPollArrayWrapper_init;
                 Java_sun_nio_ch_DevPollArrayWrapper_interrupt;
                 Java_sun_nio_ch_DevPollArrayWrapper_poll0;
@@ -74,6 +73,7 @@
 		Java_sun_nio_ch_InheritedChannel_soType0;
                 Java_sun_nio_ch_IOUtil_configureBlocking;
                 Java_sun_nio_ch_IOUtil_drain;
+		Java_sun_nio_ch_IOUtil_fdLimit;
                 Java_sun_nio_ch_IOUtil_fdVal;
                 Java_sun_nio_ch_IOUtil_initIDs;
 		Java_sun_nio_ch_IOUtil_iovMax;
@@ -113,13 +113,13 @@
 		Java_sun_nio_ch_UnixAsynchronousServerSocketChannelImpl_accept0;
 		Java_sun_nio_ch_UnixAsynchronousServerSocketChannelImpl_initIDs;
 		Java_sun_nio_ch_UnixAsynchronousSocketChannelImpl_checkConnect;
-		Java_sun_nio_ch_SolarisEventPort_init;
-		Java_sun_nio_ch_SolarisEventPort_portCreate;
-		Java_sun_nio_ch_SolarisEventPort_portClose;
-		Java_sun_nio_ch_SolarisEventPort_portAssociate;
-		Java_sun_nio_ch_SolarisEventPort_portGet;
-		Java_sun_nio_ch_SolarisEventPort_portGetn;
-		Java_sun_nio_ch_SolarisEventPort_portSend;
+		Java_sun_nio_ch_SolarisEventPort_port_1create;
+		Java_sun_nio_ch_SolarisEventPort_port_1close;
+		Java_sun_nio_ch_SolarisEventPort_port_1associate;
+		Java_sun_nio_ch_SolarisEventPort_port_1dissociate;
+		Java_sun_nio_ch_SolarisEventPort_port_1get;
+		Java_sun_nio_ch_SolarisEventPort_port_1getn;
+		Java_sun_nio_ch_SolarisEventPort_port_1send;
 		Java_sun_nio_fs_GnomeFileTypeDetector_initializeGio;
 		Java_sun_nio_fs_GnomeFileTypeDetector_probeUsingGio;
 		Java_sun_nio_fs_GnomeFileTypeDetector_initializeGnomeVfs;
--- a/src/share/classes/sun/nio/ch/IOUtil.java	Tue Sep 18 11:04:12 2012 -0700
+++ b/src/share/classes/sun/nio/ch/IOUtil.java	Tue Oct 23 03:00:10 2012 +0100
@@ -344,6 +344,8 @@
 
     static native int iovMax();
 
+    static native int fdLimit();
+
     static native void initIDs();
 
     static {
--- a/src/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java	Tue Sep 18 11:04:12 2012 -0700
+++ b/src/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java	Tue Oct 23 03:00:10 2012 +0100
@@ -71,7 +71,7 @@
     static final byte  IGNORE        = (byte)-1;
 
     // Maximum number of open file descriptors
-    static final int   OPEN_MAX      = fdLimit();
+    static final int   OPEN_MAX      = IOUtil.fdLimit();
 
     // Number of pollfd structures to create.
     // dpwrite/ioctl(DP_POLL) allows up to OPEN_MAX-1
@@ -316,5 +316,4 @@
     private native int poll0(long pollAddress, int numfds, long timeout,
                              int wfd);
     private static native void interrupt(int fd);
-    private static native int fdLimit();
 }
--- a/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java	Tue Sep 18 11:04:12 2012 -0700
+++ b/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java	Tue Oct 23 03:00:10 2012 +0100
@@ -74,7 +74,7 @@
     static final int EVENT_OFFSET     = 0;
     static final int DATA_OFFSET      = offsetofData();
     static final int FD_OFFSET        = DATA_OFFSET;
-    static final int NUM_EPOLLEVENTS  = Math.min(fdLimit(), 8192);
+    static final int NUM_EPOLLEVENTS  = Math.min(IOUtil.fdLimit(), 8192);
 
     // Base address of the native pollArray
     private final long pollArrayAddress;
@@ -296,7 +296,6 @@
                                  int epfd) throws IOException;
     private static native int sizeofEPollEvent();
     private static native int offsetofData();
-    private static native int fdLimit();
     private static native void interrupt(int fd);
     private static native void init();
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/solaris/classes/sun/nio/ch/EventPortSelectorImpl.java	Tue Oct 23 03:00:10 2012 +0100
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.ch;
+
+import java.io.IOException;
+import java.nio.channels.*;
+import java.nio.channels.spi.*;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * Selector implementation based on the Solaris event port mechanism.
+ */
+
+class EventPortSelectorImpl
+    extends SelectorImpl
+{
+    private final EventPortWrapper pollWrapper;
+
+    // Maps from file descriptors to keys
+    private Map<Integer,SelectionKeyImpl> fdToKey;
+
+    // True if this Selector has been closed
+    private boolean closed = false;
+
+    // Lock for interrupt triggering and clearing
+    private final Object interruptLock = new Object();
+    private boolean interruptTriggered = false;
+
+    /**
+     * Package private constructor called by factory method in
+     * the abstract superclass Selector.
+     */
+    EventPortSelectorImpl(SelectorProvider sp) throws IOException {
+        super(sp);
+        pollWrapper = new EventPortWrapper();
+        fdToKey = new HashMap<>();
+    }
+
+    protected int doSelect(long timeout) throws IOException {
+        if (closed)
+            throw new ClosedSelectorException();
+        processDeregisterQueue();
+        int entries;
+        try {
+            begin();
+            entries = pollWrapper.poll(timeout);
+        } finally {
+            end();
+        }
+        processDeregisterQueue();
+        int numKeysUpdated = updateSelectedKeys(entries);
+        if (pollWrapper.interrupted()) {
+            synchronized (interruptLock) {
+                interruptTriggered = false;
+            }
+        }
+        return numKeysUpdated;
+    }
+
+    private int updateSelectedKeys(int entries) {
+        int numKeysUpdated = 0;
+        for (int i=0; i<entries; i++) {
+            int nextFD = pollWrapper.getDescriptor(i);
+            SelectionKeyImpl ski = fdToKey.get(Integer.valueOf(nextFD));
+            if (ski != null) {
+                int rOps = pollWrapper.getEventOps(i);
+                if (selectedKeys.contains(ski)) {
+                    if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
+                        numKeysUpdated++;
+                    }
+                } else {
+                    ski.channel.translateAndSetReadyOps(rOps, ski);
+                    if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {
+                        selectedKeys.add(ski);
+                        numKeysUpdated++;
+                    }
+                }
+            }
+        }
+        return numKeysUpdated;
+    }
+
+    protected void implClose() throws IOException {
+        if (closed)
+            return;
+        closed = true;
+
+        // prevent further wakeup
+        synchronized (interruptLock) {
+            interruptTriggered = true;
+        }
+
+        pollWrapper.close();
+        selectedKeys = null;
+
+        // Deregister channels
+        Iterator<SelectionKey> i = keys.iterator();
+        while (i.hasNext()) {
+            SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
+            deregister(ski);
+            SelectableChannel selch = ski.channel();
+            if (!selch.isOpen() && !selch.isRegistered())
+                ((SelChImpl)selch).kill();
+            i.remove();
+        }
+    }
+
+    protected void implRegister(SelectionKeyImpl ski) {
+        int fd = IOUtil.fdVal(ski.channel.getFD());
+        fdToKey.put(Integer.valueOf(fd), ski);
+        keys.add(ski);
+    }
+
+    protected void implDereg(SelectionKeyImpl ski) throws IOException {
+        int i = ski.getIndex();
+        assert (i >= 0);
+        int fd = ski.channel.getFDVal();
+        fdToKey.remove(Integer.valueOf(fd));
+        pollWrapper.release(fd);
+        ski.setIndex(-1);
+        keys.remove(ski);
+        selectedKeys.remove(ski);
+        deregister((AbstractSelectionKey)ski);
+        SelectableChannel selch = ski.channel();
+        if (!selch.isOpen() && !selch.isRegistered())
+            ((SelChImpl)selch).kill();
+    }
+
+    public void putEventOps(SelectionKeyImpl sk, int ops) {
+        if (closed)
+            throw new ClosedSelectorException();
+        int fd = sk.channel.getFDVal();
+        pollWrapper.setInterest(fd, ops);
+    }
+
+    public Selector wakeup() {
+        synchronized (interruptLock) {
+            if (!interruptTriggered) {
+                pollWrapper.interrupt();
+                interruptTriggered = true;
+            }
+        }
+        return this;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/solaris/classes/sun/nio/ch/EventPortSelectorProvider.java	Tue Oct 23 03:00:10 2012 +0100
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.ch;
+
+import java.io.IOException;
+import java.nio.channels.*;
+import java.nio.channels.spi.*;
+
+public class EventPortSelectorProvider
+    extends SelectorProviderImpl
+{
+    public AbstractSelector openSelector() throws IOException {
+        return new EventPortSelectorImpl(this);
+    }
+
+    public Channel inheritedChannel() throws IOException {
+        return InheritedChannel.getChannel();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/solaris/classes/sun/nio/ch/EventPortWrapper.java	Tue Oct 23 03:00:10 2012 +0100
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.ch;
+
+import sun.misc.Unsafe;
+import java.io.IOException;
+import java.util.*;
+import static sun.nio.ch.SolarisEventPort.*;
+
+/**
+ * Manages a Solaris event port and manipulates a native array of pollfd structs
+ * on Solaris.
+ */
+
+class EventPortWrapper {
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+    private static final int addressSize = unsafe.addressSize();
+
+    // Maximum number of open file descriptors
+    static final int   OPEN_MAX     = IOUtil.fdLimit();
+
+    // Maximum number of events to retrive in one call to port_getn
+    static final int   POLL_MAX     =  Math.min(OPEN_MAX-1, 1024);
+
+    // initial size of the array to hold pending updates
+    private final int INITIAL_PENDING_UPDATE_SIZE = 256;
+
+    // maximum size of updateArray
+    private final int MAX_UPDATE_ARRAY_SIZE = Math.min(OPEN_MAX, 64*1024);
+
+    // special update status to indicate that it should be ignored
+    private static final byte IGNORE = -1;
+
+    // port file descriptor
+    private final int pfd;
+
+    // the poll array (populated by port_getn)
+    private final long pollArrayAddress;
+    private final AllocatedNativeObject pollArray;
+
+    // required when accessing the update* fields
+    private final Object updateLock = new Object();
+
+    // the number of pending updates
+    private int updateCount;
+
+    // queue of file descriptors with updates pending
+    private int[] updateDescriptors = new int[INITIAL_PENDING_UPDATE_SIZE];
+
+    // events for file descriptors with registration changes pending, indexed
+    // by file descriptor and stored as bytes for efficiency reasons. For
+    // file descriptors higher than MAX_UPDATE_ARRAY_SIZE (unlimited case at
+    // least then the update is stored in a map.
+    private final byte[] eventsLow = new byte[MAX_UPDATE_ARRAY_SIZE];
+    private Map<Integer,Byte> eventsHigh;
+    // Used by release and updateRegistrations to track whether a file
+    // descriptor is registered with /dev/poll.
+    private final BitSet registered = new BitSet();
+
+    // bit set to indicate if a file descriptor has been visited when
+    // processing updates (used to avoid duplicates calls to port_associate)
+    private BitSet visited = new BitSet();
+
+    EventPortWrapper() throws IOException {
+        int allocationSize = POLL_MAX * SIZEOF_PORT_EVENT;
+        pollArray = new AllocatedNativeObject(allocationSize, true);
+        pollArrayAddress = pollArray.address();
+        this.pfd = port_create();
+        if (OPEN_MAX > MAX_UPDATE_ARRAY_SIZE)
+            eventsHigh = new HashMap<>();
+    }
+
+    void close() throws IOException {
+        port_close(pfd);
+        pollArray.free();
+    }
+
+    private short getSource(int i) {
+        int offset = SIZEOF_PORT_EVENT * i + OFFSETOF_SOURCE;
+        return pollArray.getShort(offset);
+    }
+
+    int getEventOps(int i) {
+        int offset = SIZEOF_PORT_EVENT * i + OFFSETOF_EVENTS;
+        return pollArray.getInt(offset);
+    }
+
+    int getDescriptor(int i) {
+        int offset = SIZEOF_PORT_EVENT * i + OFFSETOF_OBJECT;
+        if (addressSize == 4) {
+            return pollArray.getInt(offset);
+        } else {
+            return (int) pollArray.getLong(offset);
+        }
+    }
+
+    private void setDescriptor(int i, int fd) {
+        int offset = SIZEOF_PORT_EVENT * i + OFFSETOF_OBJECT;
+        if (addressSize == 4) {
+            pollArray.putInt(offset, fd);
+        } else {
+            pollArray.putLong(offset, fd);
+        }
+    }
+
+    private void setUpdate(int fd, byte events) {
+        if (fd < MAX_UPDATE_ARRAY_SIZE) {
+            eventsLow[fd] = events;
+        } else {
+            eventsHigh.put(Integer.valueOf(fd), Byte.valueOf(events));
+        }
+    }
+
+    private byte getUpdate(int fd) {
+        if (fd < MAX_UPDATE_ARRAY_SIZE) {
+            return eventsLow[fd];
+        } else {
+            Byte result = eventsHigh.get(Integer.valueOf(fd));
+            // result should never be null
+            return result.byteValue();
+        }
+    }
+
+    int poll(long timeout) throws IOException {
+        // update registrations prior to poll
+        synchronized (updateLock) {
+
+            // process newest updates first
+            int i = updateCount - 1;
+            while (i >= 0) {
+                int fd = updateDescriptors[i];
+                if (!visited.get(fd)) {
+                    short ev = getUpdate(fd);
+                    if (ev != IGNORE) {
+                        if (ev == 0) {
+                            if (registered.get(fd)) {
+                                port_dissociate(pfd, PORT_SOURCE_FD, (long)fd);
+                                registered.clear(fd);
+                            }
+                        } else {
+                            if (port_associate(pfd, PORT_SOURCE_FD, (long)fd, ev)) {
+                                registered.set(fd);
+                            }
+                        }
+
+                    }
+                    visited.set(fd);
+                }
+                i--;
+            }
+            updateCount = 0;
+        }
+
+        // poll for events
+        int updated = port_getn(pfd, pollArrayAddress, POLL_MAX, timeout);
+
+        // after polling we need to queue all polled file descriptors as they
+        // are candidates to register for the next poll.
+        synchronized (updateLock) {
+            for (int i=0; i<updated; i++) {
+                if (getSource(i) == PORT_SOURCE_USER) {
+                    interrupted = true;
+                    setDescriptor(i, -1);
+                } else {
+                    // the default is to re-associate for the next poll
+                    int fd = getDescriptor(i);
+                    registered.clear(fd);
+                    setInterest(fd);
+                }
+            }
+        }
+
+        return updated;
+    }
+
+    private void setInterest(int fd) {
+        assert Thread.holdsLock(updateLock);
+
+        // record the file descriptor and events, expanding the
+        // respective arrays first if necessary.
+        int oldCapacity = updateDescriptors.length;
+        if (updateCount >= oldCapacity) {
+            int newCapacity = oldCapacity + INITIAL_PENDING_UPDATE_SIZE;
+            int[] newDescriptors = new int[newCapacity];
+            System.arraycopy(updateDescriptors, 0, newDescriptors, 0, oldCapacity);
+            updateDescriptors = newDescriptors;
+        }
+        updateDescriptors[updateCount++] = fd;
+        visited.clear(fd);
+    }
+
+    void setInterest(int fd, int mask) {
+        synchronized (updateLock) {
+            setInterest(fd);
+            setUpdate(fd, (byte)mask);
+            assert getUpdate(fd) == mask;
+        }
+    }
+
+    void release(int fd) {
+        synchronized (updateLock) {
+            if (registered.get(fd)) {
+                try {
+                    port_dissociate(pfd, PORT_SOURCE_FD, (long)fd);
+                } catch (IOException ioe) {
+                    InternalError x =
+                        new InternalError(ioe.getMessage());
+                    x.initCause(ioe);
+                    throw x;
+                }
+                registered.clear(fd);
+            }
+            setUpdate(fd, IGNORE);
+        }
+    }
+
+    // -- wakeup support --
+
+    private boolean interrupted;
+
+    public void interrupt() {
+        try {
+            port_send(pfd, 0);
+        } catch (IOException ioe) {
+            InternalError x =
+                new InternalError(ioe.getMessage());
+            x.initCause(ioe);
+            throw x;
+        }
+    }
+
+    boolean interrupted() {
+        return interrupted;
+    }
+
+    void clearInterrupted() {
+        interrupted = false;
+    }
+}
--- a/src/solaris/classes/sun/nio/ch/SolarisEventPort.java	Tue Sep 18 11:04:12 2012 -0700
+++ b/src/solaris/classes/sun/nio/ch/SolarisEventPort.java	Tue Oct 23 03:00:10 2012 +0100
@@ -31,8 +31,8 @@
 import sun.misc.Unsafe;
 
 /**
- * AsynchronousChannelGroup implementation based on the Solaris 10 event port
- * framework.
+ * Provides an AsynchronousChannelGroup implementation based on the Solaris 10
+ * event port framework and also provides direct access to that framework.
  */
 
 class SolarisEventPort
@@ -54,14 +54,14 @@
      *     void            *portev_user;
      * } port_event_t;
      */
-    private static final int SIZEOF_PORT_EVENT  = dependsArch(16, 24);
-    private static final int OFFSETOF_EVENTS    = 0;
-    private static final int OFFSETOF_SOURCE    = 4;
-    private static final int OFFSETOF_OBJECT    = 8;
+    static final int SIZEOF_PORT_EVENT  = dependsArch(16, 24);
+    static final int OFFSETOF_EVENTS    = 0;
+    static final int OFFSETOF_SOURCE    = 4;
+    static final int OFFSETOF_OBJECT    = 8;
 
     // port sources
-    private static final short PORT_SOURCE_USER     = 3;
-    private static final short PORT_SOURCE_FD       = 4;
+    static final short PORT_SOURCE_USER     = 3;
+    static final short PORT_SOURCE_FD       = 4;
 
     // file descriptor to event port.
     private final int port;
@@ -75,7 +75,7 @@
         super(provider, pool);
 
         // create event port
-        this.port = portCreate();
+        this.port = port_create();
     }
 
     SolarisEventPort start() {
@@ -90,12 +90,12 @@
                 return;
             closed = true;
         }
-        portClose(port);
+        port_close(port);
     }
 
     private void wakeup() {
         try {
-            portSend(port, 0);
+            port_send(port, 0);
         } catch (IOException x) {
             throw new AssertionError(x);
         }
@@ -124,7 +124,7 @@
             // send user event to wakeup each thread
             while (nThreads-- > 0) {
                 try {
-                    portSend(port, 0);
+                    port_send(port, 0);
                 } catch (IOException x) {
                     throw new AssertionError(x);
                 }
@@ -137,7 +137,7 @@
         // (re-)associate file descriptor
         // no need to translate events
         try {
-            portAssociate(port, PORT_SOURCE_FD, fd, events);
+            port_associate(port, PORT_SOURCE_FD, fd, events);
         } catch (IOException x) {
             throw new AssertionError();     // should not happen
         }
@@ -164,7 +164,7 @@
                     // A error here is fatal (thread will not be replaced)
                     replaceMe = false;
                     try {
-                        portGet(port, address);
+                        port_get(port, address);
                     } catch (IOException x) {
                         x.printStackTrace();
                         return;
@@ -220,26 +220,46 @@
         }
     }
 
-    // -- Native methods --
+    /**
+     * Creates an event port
+     */
+    static native int port_create() throws IOException;
 
-    private static native void init();
-
-    private static native int portCreate() throws IOException;
-
-    private static native void portAssociate(int port, int source, long object,
-        int events) throws IOException;
-
-    private static native void portGet(int port, long pe) throws IOException;
-
-    private static native int portGetn(int port, long address, int max)
+    /**
+     * Associates specific events of a given object with a port
+     */
+    static native boolean port_associate(int port, int source, long object, int events)
         throws IOException;
 
-    private static native void portSend(int port, int events) throws IOException;
+    /**
+     * Removes the association of an object with a port.
+     */
+    static native boolean port_dissociate(int port, int source, long object)
+        throws IOException;
 
-    private static native void portClose(int port);
+    /**
+     * Retrieves a single event from a port
+     */
+    static native void port_get(int port, long pe) throws IOException;
+
+    /**
+     * Retrieves at most {@code max} events from a port.
+     */
+    static native int port_getn(int port, long address, int max, long timeout)
+        throws IOException;
+
+    /**
+     * Sends a user-defined eventto a specified  port.
+     */
+    static native void port_send(int port, int events) throws IOException;
+
+    /**
+     * Closes a port.
+     */
+    static native void port_close(int port);
+
 
     static {
         Util.load();
-        init();
     }
 }
--- a/src/solaris/native/sun/nio/ch/DevPollArrayWrapper.c	Tue Sep 18 11:04:12 2012 -0700
+++ b/src/solaris/native/sun/nio/ch/DevPollArrayWrapper.c	Tue Oct 23 03:00:10 2012 +0100
@@ -28,9 +28,7 @@
 #include "jvm.h"
 #include "jlong.h"
 #include "sun_nio_ch_DevPollArrayWrapper.h"
-#include "java_lang_Integer.h"
 #include <sys/poll.h>
-#include <sys/resource.h>
 #include <unistd.h>
 #include <sys/time.h>
 
@@ -178,21 +176,6 @@
     return result;
 }
 
-JNIEXPORT jint JNICALL
-Java_sun_nio_ch_DevPollArrayWrapper_fdLimit(JNIEnv *env, jclass this)
-{
-    struct rlimit rlp;
-    if (getrlimit(RLIMIT_NOFILE, &rlp) < 0) {
-        JNU_ThrowIOExceptionWithLastError(env,
-                                          "getrlimit failed");
-    }
-    if (rlp.rlim_max < 0 || rlp.rlim_max > java_lang_Integer_MAX_VALUE) {
-        return java_lang_Integer_MAX_VALUE;
-    } else {
-        return (jint)rlp.rlim_max;
-    }
-}
-
 JNIEXPORT void JNICALL
 Java_sun_nio_ch_DevPollArrayWrapper_interrupt(JNIEnv *env, jclass this, jint fd)
 {
--- a/src/solaris/native/sun/nio/ch/EPollArrayWrapper.c	Tue Sep 18 11:04:12 2012 -0700
+++ b/src/solaris/native/sun/nio/ch/EPollArrayWrapper.c	Tue Oct 23 03:00:10 2012 +0100
@@ -32,7 +32,6 @@
 
 #include <dlfcn.h>
 #include <unistd.h>
-#include <sys/resource.h>
 #include <sys/time.h>
 
 #ifdef  __cplusplus
@@ -142,16 +141,6 @@
 }
 
 JNIEXPORT jint JNICALL
-Java_sun_nio_ch_EPollArrayWrapper_fdLimit(JNIEnv *env, jclass this)
-{
-    struct rlimit rlp;
-    if (getrlimit(RLIMIT_NOFILE, &rlp) < 0) {
-        JNU_ThrowIOExceptionWithLastError(env, "getrlimit failed");
-    }
-    return (jint)rlp.rlim_max;
-}
-
-JNIEXPORT jint JNICALL
 Java_sun_nio_ch_EPollArrayWrapper_sizeofEPollEvent(JNIEnv* env, jclass this)
 {
     return sizeof(struct epoll_event);
--- a/src/solaris/native/sun/nio/ch/IOUtil.c	Tue Sep 18 11:04:12 2012 -0700
+++ b/src/solaris/native/sun/nio/ch/IOUtil.c	Tue Oct 23 03:00:10 2012 +0100
@@ -25,11 +25,14 @@
 
 #include <sys/types.h>
 #include <string.h>
+#include <sys/resource.h>
+
 #include "jni.h"
 #include "jni_util.h"
 #include "jvm.h"
 #include "jlong.h"
 #include "sun_nio_ch_IOUtil.h"
+#include "java_lang_Integer.h"
 #include "nio.h"
 #include "nio_util.h"
 
@@ -118,6 +121,20 @@
     }
 }
 
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_IOUtil_fdLimit(JNIEnv *env, jclass this)
+{
+    struct rlimit rlp;
+    if (getrlimit(RLIMIT_NOFILE, &rlp) < 0) {
+        JNU_ThrowIOExceptionWithLastError(env, "getrlimit failed");
+        return -1;
+    }
+    if (rlp.rlim_max < 0 || rlp.rlim_max > java_lang_Integer_MAX_VALUE) {
+        return java_lang_Integer_MAX_VALUE;
+    } else {
+        return (jint)rlp.rlim_max;
+    }
+}
 
 /* Declared in nio_util.h for use elsewhere in NIO */
 
--- a/src/solaris/native/sun/nio/ch/SolarisEventPort.c	Tue Sep 18 11:04:12 2012 -0700
+++ b/src/solaris/native/sun/nio/ch/SolarisEventPort.c	Tue Oct 23 03:00:10 2012 +0100
@@ -32,17 +32,12 @@
 #include <stdlib.h>
 #include <dlfcn.h>
 #include <sys/types.h>
-#include <port.h>       // Solaris 10
+#include <port.h>
 
 #include "sun_nio_ch_SolarisEventPort.h"
 
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_SolarisEventPort_init(JNIEnv *env, jclass clazz)
-{
-}
-
 JNIEXPORT jint JNICALL
-Java_sun_nio_ch_SolarisEventPort_portCreate
+Java_sun_nio_ch_SolarisEventPort_port_1create
     (JNIEnv* env, jclass clazz)
 {
     int port = port_create();
@@ -53,37 +48,44 @@
 }
 
 JNIEXPORT void JNICALL
-Java_sun_nio_ch_SolarisEventPort_portClose
+Java_sun_nio_ch_SolarisEventPort_port_1close
     (JNIEnv* env, jclass clazz, jint port)
 {
     int res;
     RESTARTABLE(close(port), res);
 }
 
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_SolarisEventPort_portAssociate
+JNIEXPORT jboolean JNICALL
+Java_sun_nio_ch_SolarisEventPort_port_1associate
     (JNIEnv* env, jclass clazz, jint port, jint source, jlong objectAddress, jint events)
 {
     uintptr_t object = (uintptr_t)jlong_to_ptr(objectAddress);
+    if (port_associate((int)port, (int)source, object, (int)events, NULL) == 0) {
+        return JNI_TRUE;
+    } else {
+        if (errno != EBADFD)
+            JNU_ThrowIOExceptionWithLastError(env, "port_associate");
+        return JNI_FALSE;
+    }
+}
 
-    if (port_associate((int)port, (int)source, object, (int)events, NULL) == -1) {
-        JNU_ThrowIOExceptionWithLastError(env, "port_associate");
+JNIEXPORT jboolean JNICALL
+Java_sun_nio_ch_SolarisEventPort_port_1dissociate
+    (JNIEnv* env, jclass clazz, jint port, jint source, jlong objectAddress)
+{
+    uintptr_t object = (uintptr_t)jlong_to_ptr(objectAddress);
+
+    if (port_dissociate((int)port, (int)source, object) == 0) {
+        return JNI_TRUE;
+    } else {
+        if (errno != ENOENT)
+            JNU_ThrowIOExceptionWithLastError(env, "port_dissociate");
+        return JNI_FALSE;
     }
 }
 
 JNIEXPORT void JNICALL
-Java_sun_nio_ch_SolarisEventPort_portDissociate
-    (JNIEnv* env, jclass clazz, jint port, jint source, jlong objectAddress)
-{
-    uintptr_t object = (uintptr_t)jlong_to_ptr(objectAddress);
-
-    if (port_dissociate((int)port, (int)source, object) == -1) {
-        JNU_ThrowIOExceptionWithLastError(env, "port_dissociate");
-    }
-}
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_SolarisEventPort_portSend(JNIEnv* env, jclass clazz,
+Java_sun_nio_ch_SolarisEventPort_port_1send(JNIEnv* env, jclass clazz,
     jint port, jint events)
 {
     if (port_send((int)port, (int)events, NULL) == -1) {
@@ -92,7 +94,7 @@
 }
 
 JNIEXPORT void JNICALL
-Java_sun_nio_ch_SolarisEventPort_portGet(JNIEnv* env, jclass clazz,
+Java_sun_nio_ch_SolarisEventPort_port_1get(JNIEnv* env, jclass clazz,
     jint port, jlong eventAddress)
 {
     int res;
@@ -105,16 +107,28 @@
 }
 
 JNIEXPORT jint JNICALL
-Java_sun_nio_ch_SolarisEventPort_portGetn(JNIEnv* env, jclass clazz,
-    jint port, jlong arrayAddress, jint max)
+Java_sun_nio_ch_SolarisEventPort_port_1getn(JNIEnv* env, jclass clazz,
+    jint port, jlong arrayAddress, jint max, jlong timeout)
 {
     int res;
     uint_t n = 1;
     port_event_t* list = (port_event_t*)jlong_to_ptr(arrayAddress);
+    timespec_t ts;
+    timespec_t* tsp;
 
-    RESTARTABLE(port_getn((int)port, list, (uint_t)max, &n, NULL), res);
+    if (timeout >= 0L) {
+        ts.tv_sec = timeout / 1000;
+        ts.tv_nsec = 1000000 * (timeout % 1000);
+        tsp = &ts;
+    } else {
+        tsp = NULL;
+    }
+
+    res = port_getn((int)port, list, (uint_t)max, &n, tsp);
     if (res == -1) {
-        JNU_ThrowIOExceptionWithLastError(env, "port_getn");
+        if (errno != ETIME && errno != EINTR)
+            JNU_ThrowIOExceptionWithLastError(env, "port_getn");
     }
+
     return (jint)n;
 }
--- a/test/java/nio/channels/Selector/lots_of_updates.sh	Tue Sep 18 11:04:12 2012 -0700
+++ b/test/java/nio/channels/Selector/lots_of_updates.sh	Tue Oct 23 03:00:10 2012 +0100
@@ -46,4 +46,4 @@
     ulimit -n 2048
 fi
 
-${TESTJAVA}/bin/java LotsOfUpdates
+${TESTJAVA}/bin/java ${TESTVMOPTS} LotsOfUpdates
--- a/test/java/nio/channels/SocketChannel/Open.sh	Tue Sep 18 11:04:12 2012 -0700
+++ b/test/java/nio/channels/SocketChannel/Open.sh	Tue Oct 23 03:00:10 2012 +0100
@@ -29,7 +29,7 @@
     case "$OS" in
         SunOS )
             ulimit -n 100
-            $TESTJAVA/bin/java -classpath $TESTCLASSES Open ;;
+            $TESTJAVA/bin/java ${TESTVMOPTS} -classpath $TESTCLASSES Open ;;
         * )
             echo "unrecognized system: $OS" ;;
     esac
--- a/test/sun/nio/ch/SelProvider.java	Tue Sep 18 11:04:12 2012 -0700
+++ b/test/sun/nio/ch/SelProvider.java	Tue Oct 23 03:00:10 2012 +0100
@@ -31,19 +31,23 @@
 
 public class SelProvider {
     public static void main(String[] args) throws Exception {
-        String osname = System.getProperty("os.name");
-        String osver = System.getProperty("os.version");
-        String spName = SelectorProvider.provider().getClass().getName();
-        String expected = null;
-        if ("SunOS".equals(osname)) {
-            expected = "sun.nio.ch.DevPollSelectorProvider";
-        } else if ("Linux".equals(osname)) {
-            expected = "sun.nio.ch.EPollSelectorProvider";
-        } else if (osname.contains("OS X")) {
-            expected = "sun.nio.ch.KQueueSelectorProvider";
-        } else
-            return;
-        if (!spName.equals(expected))
+        String expected = System.getProperty("java.nio.channels.spi.SelectorProvider");
+        if (expected == null) {
+            String osname = System.getProperty("os.name");
+            String osver = System.getProperty("os.version");
+            if ("SunOS".equals(osname)) {
+                expected = "sun.nio.ch.DevPollSelectorProvider";
+            } else if ("Linux".equals(osname)) {
+                expected = "sun.nio.ch.EPollSelectorProvider";
+            } else if (osname.contains("OS X")) {
+                expected = "sun.nio.ch.KQueueSelectorProvider";
+            } else {
+                return;
+            }
+        }
+        String cn = SelectorProvider.provider().getClass().getName();
+        System.out.println(cn);
+        if (!cn.equals(expected))
             throw new Exception("failed");
     }
 }