--- a/make/CompileJavaModules.gmk Sat Mar 24 14:43:04 2018 +0900
+++ b/make/CompileJavaModules.gmk Sat Mar 24 08:49:55 2018 +0000
@@ -51,14 +51,6 @@
# data files and shouldn't go in the product
java.base_EXCLUDE_FILES += sun/text/resources/BreakIteratorRules.java
-ifneq ($(filter solaris macosx linux windows,$(OPENJDK_TARGET_OS)), )
- java.base_EXCLUDE_FILES += \
- sun/nio/ch/AbstractPollSelectorImpl.java \
- sun/nio/ch/PollSelectorImpl.java \
- sun/nio/ch/PollSelectorProvider.java \
- #
-endif
-
ifneq ($(OPENJDK_TARGET_OS), solaris)
java.base_EXCLUDE_FILES += \
SolarisLoginModule.java \
--- a/make/mapfiles/libnio/mapfile-linux Sat Mar 24 14:43:04 2018 +0900
+++ b/make/mapfiles/libnio/mapfile-linux Sat Mar 24 08:49:55 2018 +0000
@@ -118,8 +118,7 @@
Java_sun_nio_ch_Net_pollnvalValue;
Java_sun_nio_ch_Net_pollconnValue;
Java_sun_nio_ch_Net_isExclusiveBindAvailable;
- Java_sun_nio_ch_PollArrayWrapper_interrupt;
- Java_sun_nio_ch_PollArrayWrapper_poll0;
+ Java_sun_nio_ch_PollSelectorImpl_poll;
Java_sun_nio_ch_ServerSocketChannelImpl_accept0;
Java_sun_nio_ch_ServerSocketChannelImpl_initIDs;
Java_sun_nio_ch_SocketChannelImpl_checkConnect;
--- a/make/mapfiles/libnio/mapfile-macosx Sat Mar 24 14:43:04 2018 +0900
+++ b/make/mapfiles/libnio/mapfile-macosx Sat Mar 24 08:49:55 2018 +0000
@@ -118,8 +118,7 @@
Java_sun_nio_ch_Net_pollnvalValue;
Java_sun_nio_ch_Net_pollconnValue;
Java_sun_nio_ch_Net_isExclusiveBindAvailable;
- Java_sun_nio_ch_PollArrayWrapper_interrupt;
- Java_sun_nio_ch_PollArrayWrapper_poll0;
+ Java_sun_nio_ch_PollSelectorImpl_poll;
Java_sun_nio_ch_ServerSocketChannelImpl_accept0;
Java_sun_nio_ch_ServerSocketChannelImpl_initIDs;
Java_sun_nio_ch_SocketChannelImpl_checkConnect;
--- a/make/mapfiles/libnio/mapfile-solaris Sat Mar 24 14:43:04 2018 +0900
+++ b/make/mapfiles/libnio/mapfile-solaris Sat Mar 24 08:49:55 2018 +0000
@@ -116,8 +116,7 @@
Java_sun_nio_ch_Net_pollnvalValue;
Java_sun_nio_ch_Net_pollconnValue;
Java_sun_nio_ch_Net_isExclusiveBindAvailable;
- Java_sun_nio_ch_PollArrayWrapper_interrupt;
- Java_sun_nio_ch_PollArrayWrapper_poll0;
+ Java_sun_nio_ch_PollSelectorImpl_poll;
Java_sun_nio_ch_ServerSocketChannelImpl_accept0;
Java_sun_nio_ch_ServerSocketChannelImpl_initIDs;
Java_sun_nio_ch_SocketChannelImpl_checkConnect;
--- a/src/java.base/share/classes/sun/nio/ch/AbstractPollArrayWrapper.java Sat Mar 24 14:43:04 2018 +0900
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +0,0 @@
-/*
- * Copyright (c) 2001, 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;
-
-
-/**
- * Manipulates a native array of pollfd structs.
- *
- * @author Mike McCloskey
- * @since 1.4
- */
-
-public abstract class AbstractPollArrayWrapper {
-
- // Miscellaneous constants
- static final short SIZE_POLLFD = 8;
- static final short FD_OFFSET = 0;
- static final short EVENT_OFFSET = 4;
- static final short REVENT_OFFSET = 6;
-
- // The poll fd array
- protected AllocatedNativeObject pollArray;
-
- // Number of valid entries in the pollArray
- protected int totalChannels = 0;
-
- // Base address of the native pollArray
- protected long pollArrayAddress;
-
- // Access methods for fd structures
- int getEventOps(int i) {
- int offset = SIZE_POLLFD * i + EVENT_OFFSET;
- return pollArray.getShort(offset);
- }
-
- int getReventOps(int i) {
- int offset = SIZE_POLLFD * i + REVENT_OFFSET;
- return pollArray.getShort(offset);
- }
-
- int getDescriptor(int i) {
- int offset = SIZE_POLLFD * i + FD_OFFSET;
- return pollArray.getInt(offset);
- }
-
- void putEventOps(int i, int event) {
- int offset = SIZE_POLLFD * i + EVENT_OFFSET;
- pollArray.putShort(offset, (short)event);
- }
-
- void putReventOps(int i, int revent) {
- int offset = SIZE_POLLFD * i + REVENT_OFFSET;
- pollArray.putShort(offset, (short)revent);
- }
-
- void putDescriptor(int i, int fd) {
- int offset = SIZE_POLLFD * i + FD_OFFSET;
- pollArray.putInt(offset, fd);
- }
-
-}
--- a/src/java.base/share/classes/sun/nio/ch/AbstractPollSelectorImpl.java Sat Mar 24 14:43:04 2018 +0900
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,194 +0,0 @@
-/*
- * Copyright (c) 2001, 2018, 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.*;
-
-
-/**
- * An abstract selector impl.
- */
-
-abstract class AbstractPollSelectorImpl
- extends SelectorImpl
-{
-
- // The poll fd array
- PollArrayWrapper pollWrapper;
-
- // Initial capacity of the pollfd array
- protected final int INIT_CAP = 10;
-
- // The list of SelectableChannels serviced by this Selector
- protected SelectionKeyImpl[] channelArray;
-
- // In some impls the first entry of channelArray is bogus
- protected int channelOffset = 0;
-
- // The number of valid channels in this Selector's poll array
- protected int totalChannels;
-
- // True if this Selector has been closed
- private boolean closed = false;
-
- // Lock for close and cleanup
- private Object closeLock = new Object();
-
- AbstractPollSelectorImpl(SelectorProvider sp, int channels, int offset) {
- super(sp);
- this.totalChannels = channels;
- this.channelOffset = offset;
- }
-
- public void putEventOps(SelectionKeyImpl sk, int ops) {
- synchronized (closeLock) {
- if (closed)
- throw new ClosedSelectorException();
- pollWrapper.putEventOps(sk.getIndex(), ops);
- }
- }
-
- public Selector wakeup() {
- pollWrapper.interrupt();
- return this;
- }
-
- protected abstract int doSelect(long timeout) throws IOException;
-
- protected void implClose() throws IOException {
- synchronized (closeLock) {
- if (closed)
- return;
- closed = true;
- // Deregister channels
- for(int i=channelOffset; i<totalChannels; i++) {
- SelectionKeyImpl ski = channelArray[i];
- assert(ski.getIndex() != -1);
- ski.setIndex(-1);
- deregister(ski);
- SelectableChannel selch = channelArray[i].channel();
- if (!selch.isOpen() && !selch.isRegistered())
- ((SelChImpl)selch).kill();
- }
- implCloseInterrupt();
- pollWrapper.free();
- pollWrapper = null;
- channelArray = null;
- totalChannels = 0;
- }
- }
-
- protected abstract void implCloseInterrupt() throws IOException;
-
- /**
- * Copy the information in the pollfd structs into the opss
- * of the corresponding Channels. Add the ready keys to the
- * ready queue.
- */
- protected int updateSelectedKeys() {
- int numKeysUpdated = 0;
- // Skip zeroth entry; it is for interrupts only
- for (int i=channelOffset; i<totalChannels; i++) {
- int rOps = pollWrapper.getReventOps(i);
- if (rOps != 0) {
- SelectionKeyImpl sk = channelArray[i];
- pollWrapper.putReventOps(i, 0);
- if (selectedKeys.contains(sk)) {
- if (sk.channel.translateAndSetReadyOps(rOps, sk)) {
- numKeysUpdated++;
- }
- } else {
- sk.channel.translateAndSetReadyOps(rOps, sk);
- if ((sk.nioReadyOps() & sk.nioInterestOps()) != 0) {
- selectedKeys.add(sk);
- numKeysUpdated++;
- }
- }
- }
- }
- return numKeysUpdated;
- }
-
- protected void implRegister(SelectionKeyImpl ski) {
- synchronized (closeLock) {
- if (closed)
- throw new ClosedSelectorException();
-
- // Check to see if the array is large enough
- if (channelArray.length == totalChannels) {
- // Make a larger array
- int newSize = pollWrapper.totalChannels * 2;
- SelectionKeyImpl temp[] = new SelectionKeyImpl[newSize];
- // Copy over
- for (int i=channelOffset; i<totalChannels; i++)
- temp[i] = channelArray[i];
- channelArray = temp;
- // Grow the NativeObject poll array
- pollWrapper.grow(newSize);
- }
- channelArray[totalChannels] = ski;
- ski.setIndex(totalChannels);
- pollWrapper.addEntry(ski.channel);
- totalChannels++;
- keys.add(ski);
- }
- }
-
- protected void implDereg(SelectionKeyImpl ski) throws IOException {
- // Algorithm: Copy the sc from the end of the list and put it into
- // the location of the sc to be removed (since order doesn't
- // matter). Decrement the sc count. Update the index of the sc
- // that is moved.
- int i = ski.getIndex();
- assert (i >= 0);
- if (i != totalChannels - 1) {
- // Copy end one over it
- SelectionKeyImpl endChannel = channelArray[totalChannels-1];
- channelArray[i] = endChannel;
- endChannel.setIndex(i);
- pollWrapper.release(i);
- PollArrayWrapper.replaceEntry(pollWrapper, totalChannels - 1,
- pollWrapper, i);
- } else {
- pollWrapper.release(i);
- }
- // Destroy the last one
- channelArray[totalChannels-1] = null;
- totalChannels--;
- pollWrapper.totalChannels--;
- ski.setIndex(-1);
- // Remove the key from keys and selectedKeys
- keys.remove(ski);
- selectedKeys.remove(ski);
- deregister((AbstractSelectionKey)ski);
- SelectableChannel selch = ski.channel();
- if (!selch.isOpen() && !selch.isRegistered())
- ((SelChImpl)selch).kill();
- }
-}
--- a/src/java.base/share/classes/sun/nio/ch/PollSelectorProvider.java Sat Mar 24 14:43:04 2018 +0900
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2001, 2003, 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 PollSelectorProvider
- extends SelectorProviderImpl
-{
- public AbstractSelector openSelector() throws IOException {
- return new PollSelectorImpl(this);
- }
-
- public Channel inheritedChannel() throws IOException {
- return InheritedChannel.getChannel();
- }
-}
--- a/src/java.base/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java Sat Mar 24 14:43:04 2018 +0900
+++ b/src/java.base/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java Sat Mar 24 08:49:55 2018 +0000
@@ -26,12 +26,6 @@
package sun.nio.ch;
import java.io.IOException;
-import java.security.AccessController;
-import java.util.BitSet;
-import java.util.Map;
-import java.util.HashMap;
-import sun.security.action.GetIntegerAction;
-
/**
* Manipulates a native array of pollfd structs on Solaris:
@@ -48,43 +42,18 @@
class DevPollArrayWrapper {
- // Event masks
- static final short POLLIN = 0x0001;
- static final short POLLPRI = 0x0002;
- static final short POLLOUT = 0x0004;
- static final short POLLRDNORM = 0x0040;
- static final short POLLWRNORM = POLLOUT;
- static final short POLLRDBAND = 0x0080;
- static final short POLLWRBAND = 0x0100;
- static final short POLLNORM = POLLRDNORM;
- static final short POLLERR = 0x0008;
- static final short POLLHUP = 0x0010;
- static final short POLLNVAL = 0x0020;
+ // special event to remove a file descriptor from the driver
static final short POLLREMOVE = 0x0800;
- static final short POLLCONN = POLLOUT;
- // Miscellaneous constants
+ // struct pollfd constants
static final short SIZE_POLLFD = 8;
static final short FD_OFFSET = 0;
static final short EVENT_OFFSET = 4;
static final short REVENT_OFFSET = 6;
- // Special value to indicate that an update should be ignored
- static final byte IGNORE = (byte)-1;
-
- // Maximum number of open file descriptors
- static final int OPEN_MAX = IOUtil.fdLimit();
-
- // Number of pollfd structures to create.
- // dpwrite/ioctl(DP_POLL) allows up to OPEN_MAX-1
- static final int NUM_POLLFDS = Math.min(OPEN_MAX-1, 8192);
-
- // Initial size of arrays for fd registration changes
- private static final int INITIAL_PENDING_UPDATE_SIZE = 64;
-
- // maximum size of updatesLow
- private static final int MAX_UPDATE_ARRAY_SIZE = AccessController.doPrivileged(
- new GetIntegerAction("sun.nio.ch.maxUpdateArraySize", Math.min(OPEN_MAX, 64*1024)));
+ // maximum number of pollfd structure to poll or update at a time
+ // dpwrite/ioctl(DP_POLL) allows up to file descriptor limit minus 1
+ static final int NUM_POLLFDS = Math.min(IOUtil.fdLimit()-1, 1024);
// The pollfd array for results from devpoll driver
private final AllocatedNativeObject pollArray;
@@ -95,66 +64,29 @@
// The fd of the devpoll driver
private int wfd;
- // The fd of the interrupt line going out
- private int outgoingInterruptFD;
-
- // The fd of the interrupt line coming in
- private int incomingInterruptFD;
-
- // The index of the interrupt FD
- private int interruptedIndex;
-
- // Number of updated pollfd entries
- int updated;
-
- // object to synchronize fd registration changes
- private final Object updateLock = new Object();
-
- // number of file descriptors with registration changes pending
- private int updateCount;
+ DevPollArrayWrapper() throws IOException {
+ this.wfd = init();
- // file descriptors with registration changes 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();
-
- DevPollArrayWrapper() throws IOException {
int allocationSize = NUM_POLLFDS * SIZE_POLLFD;
- pollArray = new AllocatedNativeObject(allocationSize, true);
- pollArrayAddress = pollArray.address();
- wfd = init();
- if (OPEN_MAX > MAX_UPDATE_ARRAY_SIZE)
- eventsHigh = new HashMap<>();
+ this.pollArray = new AllocatedNativeObject(allocationSize, true);
+ this.pollArrayAddress = pollArray.address();
}
- void initInterrupt(int fd0, int fd1) throws IOException {
- outgoingInterruptFD = fd1;
- incomingInterruptFD = fd0;
- register(wfd, fd0, POLLIN);
+ void close() throws IOException {
+ FileDispatcherImpl.closeIntFD(wfd);
+ pollArray.free();
}
- void putReventOps(int i, int revent) {
- int offset = SIZE_POLLFD * i + REVENT_OFFSET;
- pollArray.putShort(offset, (short)revent);
+ void register(int fd, int ops) throws IOException {
+ register(wfd, fd, ops);
}
- int getEventOps(int i) {
- int offset = SIZE_POLLFD * i + EVENT_OFFSET;
- return pollArray.getShort(offset);
+ void registerMultiple(int numfds) throws IOException {
+ registerMultiple(wfd, pollArrayAddress, numfds);
}
- int getReventOps(int i) {
- int offset = SIZE_POLLFD * i + REVENT_OFFSET;
- return pollArray.getShort(offset);
+ int poll(long timeout) throws IOException {
+ return poll0(pollArrayAddress, NUM_POLLFDS, timeout, wfd);
}
int getDescriptor(int i) {
@@ -162,158 +94,24 @@
return pollArray.getInt(offset);
}
- private void setUpdateEvents(int fd, byte events) {
- if (fd < MAX_UPDATE_ARRAY_SIZE) {
- eventsLow[fd] = events;
- } else {
- eventsHigh.put(Integer.valueOf(fd), Byte.valueOf(events));
- }
- }
-
- private byte getUpdateEvents(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();
- }
- }
-
- void setInterest(int fd, int mask) {
- synchronized (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;
-
- // events are stored as bytes for efficiency reasons
- byte b = (byte)mask;
- assert (b == mask) && (b != IGNORE);
- setUpdateEvents(fd, b);
- }
- }
-
- void release(int fd) throws IOException {
- synchronized (updateLock) {
- // ignore any pending update for this file descriptor
- setUpdateEvents(fd, IGNORE);
-
- // remove from /dev/poll
- if (registered.get(fd)) {
- register(wfd, fd, POLLREMOVE);
- registered.clear(fd);
- }
- }
- }
-
- void close() throws IOException {
- FileDispatcherImpl.closeIntFD(wfd);
- pollArray.free();
- }
-
- int poll(long timeout) throws IOException {
- updateRegistrations();
- updated = poll0(pollArrayAddress, NUM_POLLFDS, timeout, wfd);
- for (int i=0; i<updated; i++) {
- if (getDescriptor(i) == incomingInterruptFD) {
- interruptedIndex = i;
- interrupted = true;
- break;
- }
- }
- return updated;
+ short getEventOps(int i) {
+ int offset = SIZE_POLLFD * i + EVENT_OFFSET;
+ return pollArray.getShort(offset);
}
- void updateRegistrations() throws IOException {
- synchronized (updateLock) {
- // Populate pollfd array with updated masks
- int j = 0;
- int index = 0;
- while (j < updateCount) {
- int fd = updateDescriptors[j];
- short events = getUpdateEvents(fd);
- boolean wasRegistered = registered.get(fd);
-
- // events = 0 => POLLREMOVE or do-nothing
- if (events != IGNORE) {
- if (events == 0) {
- if (wasRegistered) {
- events = POLLREMOVE;
- registered.clear(fd);
- } else {
- events = IGNORE;
- }
- } else {
- if (!wasRegistered) {
- registered.set(fd);
- }
- }
- }
-
- // populate pollfd array with updated event
- if (events != IGNORE) {
- // insert POLLREMOVE if changing events
- if (wasRegistered && events != POLLREMOVE) {
- putPollFD(pollArray, index, fd, POLLREMOVE);
- index++;
- }
- putPollFD(pollArray, index, fd, events);
- index++;
- if (index >= (NUM_POLLFDS-1)) {
- registerMultiple(wfd, pollArray.address(), index);
- index = 0;
- }
-
- // events for this fd now up to date
- setUpdateEvents(fd, IGNORE);
- }
- j++;
- }
-
- // write any remaining updates
- if (index > 0)
- registerMultiple(wfd, pollArray.address(), index);
-
- updateCount = 0;
- }
+ short getReventOps(int i) {
+ int offset = SIZE_POLLFD * i + REVENT_OFFSET;
+ return pollArray.getShort(offset);
}
- private void putPollFD(AllocatedNativeObject array, int index, int fd,
- short event)
- {
+ /**
+ * Updates the pollfd structure at the given index
+ */
+ void putPollFD(int index, int fd, short event) {
int structIndex = SIZE_POLLFD * index;
- array.putInt(structIndex + FD_OFFSET, fd);
- array.putShort(structIndex + EVENT_OFFSET, event);
- array.putShort(structIndex + REVENT_OFFSET, (short)0);
- }
-
- boolean interrupted = false;
-
- public void interrupt() {
- try {
- IOUtil.write1(outgoingInterruptFD, (byte)0);
- } catch (IOException ioe) {
- throw new InternalError(ioe);
- }
- }
-
- public int interruptedIndex() {
- return interruptedIndex;
- }
-
- boolean interrupted() {
- return interrupted;
- }
-
- void clearInterrupted() {
- interrupted = false;
+ pollArray.putInt(structIndex + FD_OFFSET, fd);
+ pollArray.putShort(structIndex + EVENT_OFFSET, event);
+ pollArray.putShort(structIndex + REVENT_OFFSET, (short)0);
}
private native int init() throws IOException;
--- a/src/java.base/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java Sat Mar 24 14:43:04 2018 +0900
+++ b/src/java.base/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java Sat Mar 24 08:49:55 2018 +0000
@@ -26,67 +26,71 @@
package sun.nio.ch;
import java.io.IOException;
-import java.nio.channels.*;
-import java.nio.channels.spi.*;
-import java.util.*;
+import java.nio.channels.ClosedSelectorException;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.ArrayDeque;
+import java.util.BitSet;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import static sun.nio.ch.DevPollArrayWrapper.NUM_POLLFDS;
+import static sun.nio.ch.DevPollArrayWrapper.POLLREMOVE;
/**
- * An implementation of Selector for Solaris.
+ * Solaris /dev/poll based Selector implementation
*/
+
class DevPollSelectorImpl
extends SelectorImpl
{
- // File descriptors used for interrupt
+ // provides access to /dev/poll driver
+ private final DevPollArrayWrapper pollWrapper;
+
+ // file descriptors used for interrupt
private final int fd0;
private final int fd1;
- // The poll object
- private final DevPollArrayWrapper pollWrapper;
+ // maps file descriptor to selection key, synchronize on selector
+ private final Map<Integer, SelectionKeyImpl> fdToKey = new HashMap<>();
- // Maps from file descriptors to keys
- private final Map<Integer, SelectionKeyImpl> fdToKey;
+ // file descriptors registered with /dev/poll, synchronize on selector
+ private final BitSet registered = new BitSet();
- // True if this Selector has been closed
- private boolean closed;
+ // pending new registrations/updates, queued by implRegister and putEventOps
+ private final Object updateLock = new Object();
+ private final Deque<SelectionKeyImpl> newKeys = new ArrayDeque<>();
+ private final Deque<SelectionKeyImpl> updateKeys = new ArrayDeque<>();
+ private final Deque<Integer> updateOps = new ArrayDeque<>();
- // Lock for close/cleanup
- private final Object closeLock = new Object();
-
- // Lock for interrupt triggering and clearing
+ // interrupt triggering and clearing
private final Object interruptLock = new Object();
private boolean interruptTriggered;
- /**
- * Package private constructor called by factory method in
- * the abstract superclass Selector.
- */
+
DevPollSelectorImpl(SelectorProvider sp) throws IOException {
super(sp);
- long pipeFds = IOUtil.makePipe(false);
- fd0 = (int) (pipeFds >>> 32);
- fd1 = (int) pipeFds;
+ this.pollWrapper = new DevPollArrayWrapper();
try {
- pollWrapper = new DevPollArrayWrapper();
- pollWrapper.initInterrupt(fd0, fd1);
- fdToKey = new HashMap<>();
- } catch (Throwable t) {
- try {
- FileDispatcherImpl.closeIntFD(fd0);
- } catch (IOException ioe0) {
- t.addSuppressed(ioe0);
- }
- try {
- FileDispatcherImpl.closeIntFD(fd1);
- } catch (IOException ioe1) {
- t.addSuppressed(ioe1);
- }
- throw t;
+ long fds = IOUtil.makePipe(false);
+ this.fd0 = (int) (fds >>> 32);
+ this.fd1 = (int) fds;
+ } catch (IOException ioe) {
+ pollWrapper.close();
+ throw ioe;
}
+
+ // register one end of the socket pair for wakeups
+ pollWrapper.register(fd0, Net.POLLIN);
}
private void ensureOpen() {
- if (closed)
+ if (!isOpen())
throw new ClosedSelectorException();
}
@@ -94,62 +98,123 @@
protected int doSelect(long timeout)
throws IOException
{
- ensureOpen();
+ assert Thread.holdsLock(this);
+
+ int numEntries;
+ processUpdateQueue();
processDeregisterQueue();
try {
begin();
- pollWrapper.poll(timeout);
+ numEntries = pollWrapper.poll(timeout);
} finally {
end();
}
processDeregisterQueue();
- int numKeysUpdated = updateSelectedKeys();
- if (pollWrapper.interrupted()) {
- // Clear the wakeup pipe
- pollWrapper.putReventOps(pollWrapper.interruptedIndex(), 0);
- synchronized (interruptLock) {
- pollWrapper.clearInterrupted();
- IOUtil.drain(fd0);
- interruptTriggered = false;
- }
- }
- return numKeysUpdated;
+ return updateSelectedKeys(numEntries);
}
/**
- * Update the keys whose fd's have been selected by the devpoll
- * driver. Add the ready keys to the ready queue.
+ * Process new registrations and changes to the interest ops.
*/
- private int updateSelectedKeys() {
- int entries = pollWrapper.updated;
+ private void processUpdateQueue() throws IOException {
+ assert Thread.holdsLock(this);
+
+ synchronized (updateLock) {
+ SelectionKeyImpl ski;
+
+ // new registrations
+ while ((ski = newKeys.pollFirst()) != null) {
+ if (ski.isValid()) {
+ SelChImpl ch = ski.channel;
+ int fd = ch.getFDVal();
+ SelectionKeyImpl previous = fdToKey.put(fd, ski);
+ assert previous == null;
+ assert registered.get(fd) == false;
+ }
+ }
+
+ // Translate the queued updates to changes to the set of monitored
+ // file descriptors. The changes are written to the /dev/poll driver
+ // in bulk.
+ assert updateKeys.size() == updateOps.size();
+ int index = 0;
+ while ((ski = updateKeys.pollFirst()) != null) {
+ int ops = updateOps.pollFirst();
+ int fd = ski.channel.getFDVal();
+ if (ski.isValid() && fdToKey.containsKey(fd)) {
+ if (registered.get(fd)) {
+ if (ops == 0) {
+ // remove file descriptor
+ pollWrapper.putPollFD(index++, fd, POLLREMOVE);
+ registered.clear(fd);
+ } else {
+ // change events
+ pollWrapper.putPollFD(index++, fd, POLLREMOVE);
+ pollWrapper.putPollFD(index++, fd, (short)ops);
+ }
+ } else if (ops != 0) {
+ // add file descriptor
+ pollWrapper.putPollFD(index++, fd, (short)ops);
+ registered.set(fd);
+ }
+ if (index > (NUM_POLLFDS-2)) {
+ pollWrapper.registerMultiple(index);
+ index = 0;
+ }
+ }
+ }
+
+ // write any remaining changes
+ if (index > 0)
+ pollWrapper.registerMultiple(index);
+ }
+ }
+
+ /**
+ * Update the keys whose fd's have been selected by the /dev/poll.
+ * Add the ready keys to the ready queue.
+ */
+ private int updateSelectedKeys(int numEntries) throws IOException {
+ assert Thread.holdsLock(this);
+ assert Thread.holdsLock(nioSelectedKeys());
+
+ boolean interrupted = false;
int numKeysUpdated = 0;
- for (int i=0; i<entries; i++) {
- int nextFD = pollWrapper.getDescriptor(i);
- SelectionKeyImpl ski = fdToKey.get(Integer.valueOf(nextFD));
- // ski is null in the case of an interrupt
- if (ski != null) {
- int rOps = pollWrapper.getReventOps(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++;
+ for (int i=0; i<numEntries; i++) {
+ int fd = pollWrapper.getDescriptor(i);
+ if (fd == fd0) {
+ interrupted = true;
+ } else {
+ SelectionKeyImpl ski = fdToKey.get(fd);
+ if (ski != null) {
+ int rOps = pollWrapper.getReventOps(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++;
+ }
}
}
}
}
+
+ if (interrupted) {
+ clearInterrupt();
+ }
+
return numKeysUpdated;
}
@Override
protected void implClose() throws IOException {
- if (closed)
- return;
- closed = true;
+ assert !isOpen();
+ assert Thread.holdsLock(this);
+ assert Thread.holdsLock(nioKeys());
// prevent further wakeup
synchronized (interruptLock) {
@@ -174,42 +239,67 @@
@Override
protected void implRegister(SelectionKeyImpl ski) {
- int fd = IOUtil.fdVal(ski.channel.getFD());
- fdToKey.put(Integer.valueOf(fd), ski);
+ assert Thread.holdsLock(nioKeys());
+ ensureOpen();
+ synchronized (updateLock) {
+ newKeys.addLast(ski);
+ }
keys.add(ski);
}
@Override
protected void implDereg(SelectionKeyImpl ski) throws IOException {
- int i = ski.getIndex();
- assert (i >= 0);
+ assert !ski.isValid();
+ assert Thread.holdsLock(this);
+ assert Thread.holdsLock(nioKeys());
+ assert Thread.holdsLock(nioSelectedKeys());
+
int fd = ski.channel.getFDVal();
- fdToKey.remove(Integer.valueOf(fd));
- pollWrapper.release(fd);
- ski.setIndex(-1);
+ fdToKey.remove(fd);
+ if (registered.get(fd)) {
+ pollWrapper.register(fd, POLLREMOVE);
+ registered.clear(fd);
+ }
+
+ selectedKeys.remove(ski);
keys.remove(ski);
- selectedKeys.remove(ski);
- deregister((AbstractSelectionKey)ski);
+
+ // remove from channel's key set
+ deregister(ski);
+
SelectableChannel selch = ski.channel();
if (!selch.isOpen() && !selch.isRegistered())
- ((SelChImpl)selch).kill();
+ ((SelChImpl) selch).kill();
}
@Override
- public void putEventOps(SelectionKeyImpl sk, int ops) {
+ public void putEventOps(SelectionKeyImpl ski, int ops) {
ensureOpen();
- int fd = IOUtil.fdVal(sk.channel.getFD());
- pollWrapper.setInterest(fd, ops);
+ synchronized (updateLock) {
+ updateOps.addLast(ops); // ops first in case adding the key fails
+ updateKeys.addLast(ski);
+ }
}
@Override
public Selector wakeup() {
synchronized (interruptLock) {
if (!interruptTriggered) {
- pollWrapper.interrupt();
+ try {
+ IOUtil.write1(fd1, (byte)0);
+ } catch (IOException ioe) {
+ throw new InternalError(ioe);
+ }
interruptTriggered = true;
}
}
return this;
}
+
+ private void clearInterrupt() throws IOException {
+ synchronized (interruptLock) {
+ IOUtil.drain(fd0);
+ interruptTriggered = false;
+ }
+ }
}
--- a/src/java.base/solaris/classes/sun/nio/ch/EventPortSelectorImpl.java Sat Mar 24 14:43:04 2018 +0900
+++ b/src/java.base/solaris/classes/sun/nio/ch/EventPortSelectorImpl.java Sat Mar 24 08:49:55 2018 +0000
@@ -26,11 +26,31 @@
package sun.nio.ch;
import java.io.IOException;
-import java.nio.channels.*;
-import java.nio.channels.spi.*;
-import java.util.Map;
+import java.nio.channels.ClosedSelectorException;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.ArrayDeque;
+import java.util.Deque;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import jdk.internal.misc.Unsafe;
+
+import static sun.nio.ch.SolarisEventPort.PORT_SOURCE_FD;
+import static sun.nio.ch.SolarisEventPort.PORT_SOURCE_USER;
+import static sun.nio.ch.SolarisEventPort.SIZEOF_PORT_EVENT;
+import static sun.nio.ch.SolarisEventPort.OFFSETOF_EVENTS;
+import static sun.nio.ch.SolarisEventPort.OFFSETOF_SOURCE;
+import static sun.nio.ch.SolarisEventPort.OFFSETOF_OBJECT;
+import static sun.nio.ch.SolarisEventPort.port_create;
+import static sun.nio.ch.SolarisEventPort.port_close;
+import static sun.nio.ch.SolarisEventPort.port_associate;
+import static sun.nio.ch.SolarisEventPort.port_dissociate;
+import static sun.nio.ch.SolarisEventPort.port_getn;
+import static sun.nio.ch.SolarisEventPort.port_send;
/**
* Selector implementation based on the Solaris event port mechanism.
@@ -39,89 +59,206 @@
class EventPortSelectorImpl
extends SelectorImpl
{
- private final EventPortWrapper pollWrapper;
+ // maximum number of events to retrive in one call to port_getn
+ static final int MAX_EVENTS = Math.min(IOUtil.fdLimit()-1, 1024);
- // Maps from file descriptors to keys
- private final Map<Integer, SelectionKeyImpl> fdToKey;
+ // port file descriptor
+ private final int pfd;
+
+ // the poll array (populated by port_getn)
+ private final long pollArrayAddress;
+ private final AllocatedNativeObject pollArray;
- // True if this Selector has been closed
- private boolean closed;
+ // a registration of a file descriptor with a selector
+ private static class RegEntry {
+ final SelectionKeyImpl ski;
+ int registeredOps;
+ int lastUpdate;
+ RegEntry(SelectionKeyImpl ski) {
+ this.ski = ski;
+ }
+ }
- // Lock for interrupt triggering and clearing
+ // maps a file descriptor to registration entry, synchronize on selector
+ private final Map<Integer, RegEntry> fdToRegEntry = new HashMap<>();
+
+ // the last update operation, incremented by processUpdateQueue
+ private int lastUpdate;
+
+ // pending new registrations/updates, queued by implRegister, putEventOps,
+ // and updateSelectedKeys
+ private final Object updateLock = new Object();
+ private final Deque<SelectionKeyImpl> newKeys = new ArrayDeque<>();
+ private final Deque<SelectionKeyImpl> updateKeys = new ArrayDeque<>();
+ private final Deque<Integer> updateOps = new ArrayDeque<>();
+
+ // interrupt triggering and clearing
private final Object interruptLock = new Object();
private boolean interruptTriggered;
- /**
- * 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<>();
+
+ this.pfd = port_create();
+
+ int allocationSize = MAX_EVENTS * SIZEOF_PORT_EVENT;
+ this.pollArray = new AllocatedNativeObject(allocationSize, false);
+ this.pollArrayAddress = pollArray.address();
}
private void ensureOpen() {
- if (closed)
+ if (!isOpen())
throw new ClosedSelectorException();
}
@Override
protected int doSelect(long timeout) throws IOException {
- ensureOpen();
+ assert Thread.holdsLock(this);
+
+ int numEvents;
+ processUpdateQueue();
processDeregisterQueue();
- int entries;
try {
begin();
- entries = pollWrapper.poll(timeout);
+
+ long to = timeout;
+ boolean timedPoll = (to > 0);
+ do {
+ long startTime = timedPoll ? System.nanoTime() : 0;
+ numEvents = port_getn(pfd, pollArrayAddress, MAX_EVENTS, to);
+ if (numEvents == IOStatus.INTERRUPTED && timedPoll) {
+ // timed poll interrupted so need to adjust timeout
+ long adjust = System.nanoTime() - startTime;
+ to -= TimeUnit.MILLISECONDS.convert(adjust, TimeUnit.NANOSECONDS);
+ if (to <= 0) {
+ // timeout also expired so no retry
+ numEvents = 0;
+ }
+ }
+ } while (numEvents == IOStatus.INTERRUPTED);
+ assert IOStatus.check(numEvents);
+
} finally {
end();
}
processDeregisterQueue();
- int numKeysUpdated = updateSelectedKeys(entries);
- if (pollWrapper.interrupted()) {
- synchronized (interruptLock) {
- interruptTriggered = false;
+ return processPortEvents(numEvents);
+ }
+
+ /**
+ * Process new registrations and changes to the interest ops.
+ */
+ private void processUpdateQueue() throws IOException {
+ assert Thread.holdsLock(this);
+
+ // bump lastUpdate to ensure that the interest ops are changed at most
+ // once per bulk update
+ lastUpdate++;
+
+ synchronized (updateLock) {
+ SelectionKeyImpl ski;
+
+ // new registrations
+ while ((ski = newKeys.pollFirst()) != null) {
+ if (ski.isValid()) {
+ SelChImpl ch = ski.channel;
+ int fd = ch.getFDVal();
+ RegEntry previous = fdToRegEntry.put(fd, new RegEntry(ski));
+ assert previous == null;
+ }
+ }
+
+ // changes to interest ops
+ assert updateKeys.size() == updateOps.size();
+ while ((ski = updateKeys.pollFirst()) != null) {
+ int ops = updateOps.pollFirst();
+ int fd = ski.channel.getFDVal();
+ RegEntry e = fdToRegEntry.get(fd);
+ if (ski.isValid() && (e != null) && (e.lastUpdate != lastUpdate)) {
+ assert e.ski == ski;
+ if ((ops != e.registeredOps)) {
+ if (ops == 0) {
+ port_dissociate(pfd, PORT_SOURCE_FD, fd);
+ } else {
+ port_associate(pfd, PORT_SOURCE_FD, fd, ops);
+ }
+ e.registeredOps = ops;
+ }
+ e.lastUpdate = lastUpdate;
+ }
}
}
- return numKeysUpdated;
}
- private int updateSelectedKeys(int entries) {
+ /**
+ * Process the port events. This method updates the keys of file descriptors
+ * that were polled. It also re-queues the key so that the file descriptor
+ * is re-associated at the next select operation.
+ *
+ * @return the number of selection keys updated.
+ */
+ private int processPortEvents(int numEvents) throws IOException {
+ assert Thread.holdsLock(this);
+ assert Thread.holdsLock(nioSelectedKeys());
+
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++;
+ boolean interrupted = false;
+
+ synchronized (updateLock) {
+ for (int i = 0; i < numEvents; i++) {
+ short source = getSource(i);
+ if (source == PORT_SOURCE_FD) {
+ int fd = getDescriptor(i);
+ RegEntry e = fdToRegEntry.get(fd);
+ if (e != null) {
+ SelectionKeyImpl ski = e.ski;
+ int rOps = 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++;
+ }
+ }
+
+ // queue selection key so that it is re-associated at
+ // next select. Push to end of deque so that changes to
+ // the interest ops are processed first
+ updateKeys.addLast(ski);
+ updateOps.addLast(e.registeredOps);
+ e.registeredOps = 0;
}
+ } else if (source == PORT_SOURCE_USER) {
+ interrupted = true;
} else {
- ski.channel.translateAndSetReadyOps(rOps, ski);
- if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {
- selectedKeys.add(ski);
- numKeysUpdated++;
- }
+ assert false;
}
}
}
+
+ if (interrupted) {
+ clearInterrupt();
+ }
return numKeysUpdated;
}
@Override
protected void implClose() throws IOException {
- if (closed)
- return;
- closed = true;
+ assert !isOpen();
+ assert Thread.holdsLock(this);
+ assert Thread.holdsLock(nioKeys());
// prevent further wakeup
synchronized (interruptLock) {
interruptTriggered = true;
}
- pollWrapper.close();
+ port_close(pfd);
+ pollArray.free();
// Deregister channels
Iterator<SelectionKey> i = keys.iterator();
@@ -137,42 +274,83 @@
@Override
protected void implRegister(SelectionKeyImpl ski) {
- int fd = IOUtil.fdVal(ski.channel.getFD());
- fdToKey.put(Integer.valueOf(fd), ski);
+ assert Thread.holdsLock(nioKeys());
+ ensureOpen();
+ synchronized (updateLock) {
+ newKeys.addLast(ski);
+ }
keys.add(ski);
}
@Override
protected void implDereg(SelectionKeyImpl ski) throws IOException {
- int i = ski.getIndex();
- assert (i >= 0);
+ assert !ski.isValid();
+ assert Thread.holdsLock(this);
+ assert Thread.holdsLock(nioKeys());
+ assert Thread.holdsLock(nioSelectedKeys());
+
int fd = ski.channel.getFDVal();
- fdToKey.remove(Integer.valueOf(fd));
- pollWrapper.release(fd);
- ski.setIndex(-1);
+ RegEntry e = fdToRegEntry.remove(fd);
+ if (e != null && e.registeredOps != 0) {
+ port_dissociate(pfd, PORT_SOURCE_FD, fd);
+ }
+
+ selectedKeys.remove(ski);
keys.remove(ski);
- selectedKeys.remove(ski);
- deregister((AbstractSelectionKey)ski);
+
+ // remove from channel's key set
+ deregister(ski);
+
SelectableChannel selch = ski.channel();
if (!selch.isOpen() && !selch.isRegistered())
- ((SelChImpl)selch).kill();
+ ((SelChImpl) selch).kill();
}
@Override
- public void putEventOps(SelectionKeyImpl sk, int ops) {
+ public void putEventOps(SelectionKeyImpl ski, int ops) {
ensureOpen();
- int fd = sk.channel.getFDVal();
- pollWrapper.setInterest(fd, ops);
+ synchronized (updateLock) {
+ // push to front of deque so that it processed before other
+ // updates for the same key.
+ updateOps.addFirst(ops);
+ updateKeys.addFirst(ski);
+ }
}
@Override
public Selector wakeup() {
synchronized (interruptLock) {
if (!interruptTriggered) {
- pollWrapper.interrupt();
+ try {
+ port_send(pfd, 0);
+ } catch (IOException ioe) {
+ throw new InternalError(ioe);
+ }
interruptTriggered = true;
}
}
return this;
}
+
+ private void clearInterrupt() throws IOException {
+ synchronized (interruptLock) {
+ interruptTriggered = false;
+ }
+ }
+
+ private short getSource(int i) {
+ int offset = SIZEOF_PORT_EVENT * i + OFFSETOF_SOURCE;
+ return pollArray.getShort(offset);
+ }
+
+ private int getEventOps(int i) {
+ int offset = SIZEOF_PORT_EVENT * i + OFFSETOF_EVENTS;
+ return pollArray.getInt(offset);
+ }
+
+ private int getDescriptor(int i) {
+ //assert Unsafe.getUnsafe().addressSize() == 8;
+ int offset = SIZEOF_PORT_EVENT * i + OFFSETOF_OBJECT;
+ return (int) pollArray.getLong(offset);
+ }
}
--- a/src/java.base/solaris/classes/sun/nio/ch/EventPortWrapper.java Sat Mar 24 14:43:04 2018 +0900
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,276 +0,0 @@
-/*
- * Copyright (c) 2012, 2018, 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.security.AccessController;
-import java.util.BitSet;
-import java.util.HashMap;
-import java.util.Map;
-
-import jdk.internal.misc.Unsafe;
-import sun.security.action.GetIntegerAction;
-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 static final int MAX_UPDATE_ARRAY_SIZE = AccessController.doPrivileged(
- new GetIntegerAction("sun.nio.ch.maxUpdateArraySize", 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 numEntries;
- long to = timeout;
- boolean timedPoll = (to > 0);
- do {
- long startTime = timedPoll ? System.currentTimeMillis() : 0;
- numEntries = port_getn(pfd, pollArrayAddress, POLL_MAX, timeout);
- if (numEntries == IOStatus.INTERRUPTED && timedPoll) {
- // timed poll interrupted so need to adjust timeout
- to -= System.currentTimeMillis() - startTime;
- if (to <= 0) {
- // timeout also expired so no retry
- numEntries = 0;
- }
- }
- } while (numEntries == IOStatus.INTERRUPTED);
-
- // 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<numEntries; 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 numEntries;
- }
-
- 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) {
- throw new InternalError(ioe);
- }
- registered.clear(fd);
- }
- setUpdate(fd, IGNORE);
- }
- }
-
- // -- wakeup support --
-
- private boolean interrupted;
-
- public void interrupt() {
- try {
- port_send(pfd, 0);
- } catch (IOException ioe) {
- throw new InternalError(ioe);
- }
- }
-
- boolean interrupted() {
- return interrupted;
- }
-
- void clearInterrupted() {
- interrupted = false;
- }
-}
--- a/src/java.base/unix/classes/sun/nio/ch/PollArrayWrapper.java Sat Mar 24 14:43:04 2018 +0900
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,128 +0,0 @@
-/*
- * Copyright (c) 2001, 2013, 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;
-
-
-/**
- * Manipulates a native array of pollfd structs on Solaris:
- *
- * typedef struct pollfd {
- * int fd;
- * short events;
- * short revents;
- * } pollfd_t;
- *
- * @author Mike McCloskey
- * @since 1.4
- */
-
-public class PollArrayWrapper extends AbstractPollArrayWrapper {
-
- // File descriptor to write for interrupt
- int interruptFD;
-
- PollArrayWrapper(int newSize) {
- newSize = (newSize + 1) * SIZE_POLLFD;
- pollArray = new AllocatedNativeObject(newSize, false);
- pollArrayAddress = pollArray.address();
- totalChannels = 1;
- }
-
- void initInterrupt(int fd0, int fd1) {
- interruptFD = fd1;
- putDescriptor(0, fd0);
- putEventOps(0, Net.POLLIN);
- putReventOps(0, 0);
- }
-
- void release(int i) {
- return;
- }
-
- void free() {
- pollArray.free();
- }
-
- /**
- * Prepare another pollfd struct for use.
- */
- void addEntry(SelChImpl sc) {
- putDescriptor(totalChannels, IOUtil.fdVal(sc.getFD()));
- putEventOps(totalChannels, 0);
- putReventOps(totalChannels, 0);
- totalChannels++;
- }
-
- /**
- * Writes the pollfd entry from the source wrapper at the source index
- * over the entry in the target wrapper at the target index. The source
- * array remains unchanged unless the source array and the target are
- * the same array.
- */
- static void replaceEntry(PollArrayWrapper source, int sindex,
- PollArrayWrapper target, int tindex) {
- target.putDescriptor(tindex, source.getDescriptor(sindex));
- target.putEventOps(tindex, source.getEventOps(sindex));
- target.putReventOps(tindex, source.getReventOps(sindex));
- }
-
- /**
- * Grows the pollfd array to a size that will accommodate newSize
- * pollfd entries. This method does no checking of the newSize
- * to determine if it is in fact bigger than the old size: it
- * always reallocates an array of the new size.
- */
- void grow(int newSize) {
- // create new array
- PollArrayWrapper temp = new PollArrayWrapper(newSize);
-
- // Copy over existing entries
- for (int i=0; i<totalChannels; i++)
- replaceEntry(this, i, temp, i);
-
- // Swap new array into pollArray field
- pollArray.free();
- pollArray = temp.pollArray;
- pollArrayAddress = pollArray.address();
- }
-
- int poll(int numfds, int offset, long timeout) {
- return poll0(pollArrayAddress + (offset * SIZE_POLLFD),
- numfds, timeout);
- }
-
- public void interrupt() {
- interrupt(interruptFD);
- }
-
- private native int poll0(long pollAddress, int numfds, long timeout);
-
- private static native void interrupt(int fd);
-
- static {
- IOUtil.load();
- }
-}
--- a/src/java.base/unix/classes/sun/nio/ch/PollSelectorImpl.java Sat Mar 24 14:43:04 2018 +0900
+++ b/src/java.base/unix/classes/sun/nio/ch/PollSelectorImpl.java Sat Mar 24 08:49:55 2018 +0000
@@ -22,104 +22,404 @@
* 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.*;
+import java.nio.channels.ClosedSelectorException;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import jdk.internal.misc.Unsafe;
/**
- * An implementation of Selector for Solaris.
+ * Selector implementation based on poll
*/
-class PollSelectorImpl
- extends AbstractPollSelectorImpl
-{
+class PollSelectorImpl extends SelectorImpl {
+
+ // initial capacity of poll array
+ private static final int INITIAL_CAPACITY = 16;
- // File descriptors used for interrupt
- private int fd0;
- private int fd1;
+ // poll array, grows as needed
+ private int pollArrayCapacity = INITIAL_CAPACITY;
+ private int pollArraySize;
+ private AllocatedNativeObject pollArray;
- // Lock for interrupt triggering and clearing
- private Object interruptLock = new Object();
- private boolean interruptTriggered = false;
+ // file descriptors used for interrupt
+ private final int fd0;
+ private final int fd1;
+
+ // keys for file descriptors in poll array, synchronize on selector
+ private final List<SelectionKeyImpl> pollKeys = new ArrayList<>();
- /**
- * Package private constructor called by factory method in
- * the abstract superclass Selector.
- */
+ // pending updates, queued by putEventOps
+ private final Object updateLock = new Object();
+ private final Deque<SelectionKeyImpl> updateKeys = new ArrayDeque<>();
+ private final Deque<Integer> updateOps = new ArrayDeque<>();
+
+ // interrupt triggering and clearing
+ private final Object interruptLock = new Object();
+ private boolean interruptTriggered;
+
PollSelectorImpl(SelectorProvider sp) throws IOException {
- super(sp, 1, 1);
- long pipeFds = IOUtil.makePipe(false);
- fd0 = (int) (pipeFds >>> 32);
- fd1 = (int) pipeFds;
+ super(sp);
+
+ int size = pollArrayCapacity * SIZE_POLLFD;
+ this.pollArray = new AllocatedNativeObject(size, false);
+
try {
- pollWrapper = new PollArrayWrapper(INIT_CAP);
- pollWrapper.initInterrupt(fd0, fd1);
- channelArray = new SelectionKeyImpl[INIT_CAP];
- } catch (Throwable t) {
- try {
- FileDispatcherImpl.closeIntFD(fd0);
- } catch (IOException ioe0) {
- t.addSuppressed(ioe0);
- }
- try {
- FileDispatcherImpl.closeIntFD(fd1);
- } catch (IOException ioe1) {
- t.addSuppressed(ioe1);
- }
- throw t;
+ long fds = IOUtil.makePipe(false);
+ this.fd0 = (int) (fds >>> 32);
+ this.fd1 = (int) fds;
+ } catch (IOException ioe) {
+ pollArray.free();
+ throw ioe;
+ }
+
+ // wakeup support
+ synchronized (this) {
+ setFirst(fd0, Net.POLLIN);
}
}
- protected int doSelect(long timeout)
- throws IOException
- {
- if (channelArray == null)
+ private void ensureOpen() {
+ if (!isOpen())
throw new ClosedSelectorException();
+ }
+
+ @Override
+ protected int doSelect(long timeout) throws IOException {
+ assert Thread.holdsLock(this);
+
+ processUpdateQueue();
processDeregisterQueue();
try {
begin();
- pollWrapper.poll(totalChannels, 0, timeout);
+
+ int to = (int) Math.min(timeout, Integer.MAX_VALUE); // max poll timeout
+ boolean timedPoll = (to > 0);
+ int numPolled;
+ do {
+ long startTime = timedPoll ? System.nanoTime() : 0;
+ numPolled = poll(pollArray.address(), pollArraySize, to);
+ if (numPolled == IOStatus.INTERRUPTED && timedPoll) {
+ // timed poll interrupted so need to adjust timeout
+ long adjust = System.nanoTime() - startTime;
+ to -= TimeUnit.MILLISECONDS.convert(adjust, TimeUnit.NANOSECONDS);
+ if (to <= 0) {
+ // timeout expired so no retry
+ numPolled = 0;
+ }
+ }
+ } while (numPolled == IOStatus.INTERRUPTED);
+ assert numPolled <= pollArraySize;
+
} finally {
end();
}
+
processDeregisterQueue();
- int numKeysUpdated = updateSelectedKeys();
- if (pollWrapper.getReventOps(0) != 0) {
- // Clear the wakeup pipe
- pollWrapper.putReventOps(0, 0);
- synchronized (interruptLock) {
- IOUtil.drain(fd0);
- interruptTriggered = false;
+ return updateSelectedKeys();
+ }
+
+ /**
+ * Process changes to the interest ops.
+ */
+ private void processUpdateQueue() {
+ assert Thread.holdsLock(this);
+
+ synchronized (updateLock) {
+ assert updateKeys.size() == updateOps.size();
+
+ SelectionKeyImpl ski;
+ while ((ski = updateKeys.pollFirst()) != null) {
+ int ops = updateOps.pollFirst();
+ if (ski.isValid()) {
+ int index = ski.getIndex();
+ assert index >= 0 && index < pollArraySize;
+ if (index > 0) {
+ assert pollKeys.get(index) == ski;
+ if (ops == 0) {
+ remove(ski);
+ } else {
+ update(ski, ops);
+ }
+ } else if (ops != 0) {
+ add(ski, ops);
+ }
+ }
}
}
+ }
+
+ /**
+ * Update the keys whose fd's have been selected by kqueue.
+ * Add the ready keys to the selected key set.
+ * If the interrupt fd has been selected, drain it and clear the interrupt.
+ */
+ private int updateSelectedKeys() throws IOException {
+ assert Thread.holdsLock(this);
+ assert Thread.holdsLock(nioSelectedKeys());
+ assert pollArraySize > 0 && pollArraySize == pollKeys.size();
+
+ int numKeysUpdated = 0;
+ for (int i = 1; i < pollArraySize; i++) {
+ int rOps = getReventOps(i);
+ if (rOps != 0) {
+ SelectionKeyImpl ski = pollKeys.get(i);
+ assert ski.channel.getFDVal() == getDescriptor(i);
+ if (ski.isValid()) {
+ 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++;
+ }
+ }
+ }
+ }
+ }
+
+ // check for interrupt
+ if (getReventOps(0) != 0) {
+ assert getDescriptor(0) == fd0;
+ clearInterrupt();
+ }
+
return numKeysUpdated;
}
- protected void implCloseInterrupt() throws IOException {
+ @Override
+ protected void implClose() throws IOException {
+ assert !isOpen();
+ assert Thread.holdsLock(this);
+ assert Thread.holdsLock(nioKeys());
+
// prevent further wakeup
synchronized (interruptLock) {
interruptTriggered = true;
}
+
+ pollArray.free();
FileDispatcherImpl.closeIntFD(fd0);
FileDispatcherImpl.closeIntFD(fd1);
- fd0 = -1;
- fd1 = -1;
- pollWrapper.release(0);
+
+ // Deregister channels
+ Iterator<SelectionKey> i = keys.iterator();
+ while (i.hasNext()) {
+ SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
+ ski.setIndex(-1);
+ deregister(ski);
+ SelectableChannel selch = ski.channel();
+ if (!selch.isOpen() && !selch.isRegistered())
+ ((SelChImpl)selch).kill();
+ i.remove();
+ }
+ }
+
+ @Override
+ protected void implRegister(SelectionKeyImpl ski) {
+ assert ski.getIndex() == 0;
+ assert Thread.holdsLock(nioKeys());
+
+ ensureOpen();
+ keys.add(ski);
}
+ @Override
+ protected void implDereg(SelectionKeyImpl ski) throws IOException {
+ assert !ski.isValid();
+ assert Thread.holdsLock(this);
+ assert Thread.holdsLock(nioKeys());
+ assert Thread.holdsLock(nioSelectedKeys());
+
+ // remove from poll array
+ int index = ski.getIndex();
+ if (index > 0) {
+ remove(ski);
+ }
+
+ // remove from selected-key and key set
+ selectedKeys.remove(ski);
+ keys.remove(ski);
+
+ // remove from channel's key set
+ deregister(ski);
+
+ SelectableChannel selch = ski.channel();
+ if (!selch.isOpen() && !selch.isRegistered())
+ ((SelChImpl) selch).kill();
+ }
+
+ @Override
+ public void putEventOps(SelectionKeyImpl ski, int ops) {
+ ensureOpen();
+ synchronized (updateLock) {
+ updateOps.addLast(ops); // ops first in case adding the key fails
+ updateKeys.addLast(ski);
+ }
+ }
+
+ @Override
public Selector wakeup() {
synchronized (interruptLock) {
if (!interruptTriggered) {
- pollWrapper.interrupt();
+ try {
+ IOUtil.write1(fd1, (byte)0);
+ } catch (IOException ioe) {
+ throw new InternalError(ioe);
+ }
interruptTriggered = true;
}
}
return this;
}
+ private void clearInterrupt() throws IOException {
+ synchronized (interruptLock) {
+ IOUtil.drain(fd0);
+ interruptTriggered = false;
+ }
+ }
+
+ /**
+ * Sets the first pollfd enty in the poll array to the given fd
+ */
+ private void setFirst(int fd, int ops) {
+ assert pollArraySize == 0;
+ assert pollKeys.isEmpty();
+
+ putDescriptor(0, fd);
+ putEventOps(0, ops);
+ pollArraySize = 1;
+
+ pollKeys.add(null); // dummy element
+ }
+
+ /**
+ * Adds a pollfd entry to the poll array, expanding the poll array if needed.
+ */
+ private void add(SelectionKeyImpl ski, int ops) {
+ expandIfNeeded();
+
+ int index = pollArraySize;
+ assert index > 0;
+ putDescriptor(index, ski.channel.getFDVal());
+ putEventOps(index, ops);
+ putReventOps(index, 0);
+ ski.setIndex(index);
+ pollArraySize++;
+
+ pollKeys.add(ski);
+ assert pollKeys.size() == pollArraySize;
+ }
+
+ /**
+ * Update the events of pollfd entry.
+ */
+ private void update(SelectionKeyImpl ski, int ops) {
+ int index = ski.getIndex();
+ assert index > 0 && index < pollArraySize;
+ assert getDescriptor(index) == ski.channel.getFDVal();
+ putEventOps(index, ops);
+ }
+
+ /**
+ * Removes a pollfd entry from the poll array
+ */
+ private void remove(SelectionKeyImpl ski) {
+ int index = ski.getIndex();
+ assert index > 0 && index < pollArraySize;
+ assert getDescriptor(index) == ski.channel.getFDVal();
+
+ // replace pollfd at index with the last pollfd in array
+ int lastIndex = pollArraySize - 1;
+ if (lastIndex != index) {
+ SelectionKeyImpl lastKey = pollKeys.get(lastIndex);
+ assert lastKey.getIndex() == lastIndex;
+ int lastFd = getDescriptor(lastIndex);
+ int lastOps = getEventOps(lastIndex);
+ int lastRevents = getReventOps(lastIndex);
+ assert lastKey.channel.getFDVal() == lastFd;
+ putDescriptor(index, lastFd);
+ putEventOps(index, lastOps);
+ putReventOps(index, lastRevents);
+ pollKeys.set(index, lastKey);
+ lastKey.setIndex(index);
+ }
+ pollKeys.remove(lastIndex);
+ pollArraySize--;
+ assert pollKeys.size() == pollArraySize;
+
+ ski.setIndex(0);
+ }
+
+ /**
+ * Expand poll array if at capacity
+ */
+ private void expandIfNeeded() {
+ if (pollArraySize == pollArrayCapacity) {
+ int oldSize = pollArrayCapacity * SIZE_POLLFD;
+ int newCapacity = pollArrayCapacity + INITIAL_CAPACITY;
+ int newSize = newCapacity * SIZE_POLLFD;
+ AllocatedNativeObject newPollArray = new AllocatedNativeObject(newSize, false);
+ Unsafe.getUnsafe().copyMemory(pollArray.address(), newPollArray.address(), oldSize);
+ pollArray.free();
+ pollArray = newPollArray;
+ pollArrayCapacity = newCapacity;
+ }
+ }
+
+ private static final short SIZE_POLLFD = 8;
+ private static final short FD_OFFSET = 0;
+ private static final short EVENT_OFFSET = 4;
+ private static final short REVENT_OFFSET = 6;
+
+ private void putDescriptor(int i, int fd) {
+ int offset = SIZE_POLLFD * i + FD_OFFSET;
+ pollArray.putInt(offset, fd);
+ }
+
+ private int getDescriptor(int i) {
+ int offset = SIZE_POLLFD * i + FD_OFFSET;
+ return pollArray.getInt(offset);
+ }
+
+ private void putEventOps(int i, int event) {
+ int offset = SIZE_POLLFD * i + EVENT_OFFSET;
+ pollArray.putShort(offset, (short)event);
+ }
+
+ private int getEventOps(int i) {
+ int offset = SIZE_POLLFD * i + EVENT_OFFSET;
+ return pollArray.getShort(offset);
+ }
+
+ private void putReventOps(int i, int revent) {
+ int offset = SIZE_POLLFD * i + REVENT_OFFSET;
+ pollArray.putShort(offset, (short)revent);
+ }
+
+ private int getReventOps(int i) {
+ int offset = SIZE_POLLFD * i + REVENT_OFFSET;
+ return pollArray.getShort(offset);
+ }
+
+ private static native int poll(long pollAddress, int numfds, int timeout);
+
+ static {
+ IOUtil.load();
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/unix/classes/sun/nio/ch/PollSelectorProvider.java Sat Mar 24 08:49:55 2018 +0000
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2001, 2018, 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.Channel;
+import java.nio.channels.spi.AbstractSelector;
+
+public class PollSelectorProvider
+ extends SelectorProviderImpl
+{
+ public AbstractSelector openSelector() throws IOException {
+ return new PollSelectorImpl(this);
+ }
+
+ public Channel inheritedChannel() throws IOException {
+ return InheritedChannel.getChannel();
+ }
+}
--- a/src/java.base/unix/native/libnio/ch/Net.c Sat Mar 24 14:43:04 2018 +0900
+++ b/src/java.base/unix/native/libnio/ch/Net.c Sat Mar 24 08:49:55 2018 +0000
@@ -40,7 +40,6 @@
#include "net_util_md.h"
#include "nio_util.h"
#include "nio.h"
-#include "sun_nio_ch_PollArrayWrapper.h"
#ifdef _AIX
#include <sys/utsname.h>
--- a/src/java.base/unix/native/libnio/ch/PollArrayWrapper.c Sat Mar 24 14:43:04 2018 +0900
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-/*
- * Copyright (c) 2001, 2005, 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.
- */
-
-#include "jni.h"
-#include "jni_util.h"
-#include "jvm.h"
-#include "jlong.h"
-#include "sun_nio_ch_PollArrayWrapper.h"
-#include <poll.h>
-#include <unistd.h>
-#include <sys/time.h>
-
-#define RESTARTABLE(_cmd, _result) do { \
- do { \
- _result = _cmd; \
- } while((_result == -1) && (errno == EINTR)); \
-} while(0)
-
-static int
-ipoll(struct pollfd fds[], unsigned int nfds, int timeout)
-{
- jlong start, now;
- int remaining = timeout;
- struct timeval t;
- int diff;
-
- gettimeofday(&t, NULL);
- start = t.tv_sec * 1000 + t.tv_usec / 1000;
-
- for (;;) {
- int res = poll(fds, nfds, remaining);
- if (res < 0 && errno == EINTR) {
- if (remaining >= 0) {
- gettimeofday(&t, NULL);
- now = t.tv_sec * 1000 + t.tv_usec / 1000;
- diff = now - start;
- remaining -= diff;
- if (diff < 0 || remaining <= 0) {
- return 0;
- }
- start = now;
- }
- } else {
- return res;
- }
- }
-}
-
-JNIEXPORT jint JNICALL
-Java_sun_nio_ch_PollArrayWrapper_poll0(JNIEnv *env, jobject this,
- jlong address, jint numfds,
- jlong timeout)
-{
- struct pollfd *a;
- int err = 0;
-
- a = (struct pollfd *) jlong_to_ptr(address);
-
- if (timeout <= 0) { /* Indefinite or no wait */
- RESTARTABLE (poll(a, numfds, timeout), err);
- } else { /* Bounded wait; bounded restarts */
- err = ipoll(a, numfds, timeout);
- }
-
- if (err < 0) {
- JNU_ThrowIOExceptionWithLastError(env, "Poll failed");
- }
- return (jint)err;
-}
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_PollArrayWrapper_interrupt(JNIEnv *env, jobject this, jint fd)
-{
- int fakebuf[1];
- fakebuf[0] = 1;
- if (write(fd, fakebuf, 1) < 0) {
- JNU_ThrowIOExceptionWithLastError(env,
- "Write to interrupt fd failed");
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/unix/native/libnio/ch/PollSelectorImpl.c Sat Mar 24 08:49:55 2018 +0000
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2001, 2018, 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.
+ */
+
+#include <poll.h>
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jvm.h"
+#include "jlong.h"
+#include "nio.h"
+#include "sun_nio_ch_PollSelectorImpl.h"
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_PollSelectorImpl_poll(JNIEnv *env, jclass clazz,
+ jlong address, jint numfds,
+ jint timeout)
+{
+ struct pollfd *a;
+ int res;
+
+ a = (struct pollfd *) jlong_to_ptr(address);
+ res = poll(a, numfds, timeout);
+ if (res < 0) {
+ if (errno == EINTR) {
+ return IOS_INTERRUPTED;
+ } else {
+ JNU_ThrowIOExceptionWithLastError(env, "poll failed");
+ return IOS_THROWN;
+ }
+ }
+ return (jint) res;
+}
+
--- a/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpChannelImpl.java Sat Mar 24 14:43:04 2018 +0900
+++ b/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpChannelImpl.java Sat Mar 24 08:49:55 2018 +0000
@@ -58,7 +58,6 @@
import sun.nio.ch.IOUtil;
import sun.nio.ch.NativeThread;
import sun.nio.ch.Net;
-import sun.nio.ch.PollArrayWrapper;
import sun.nio.ch.SelChImpl;
import sun.nio.ch.SelectionKeyImpl;
import sun.nio.ch.Util;
--- a/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpMultiChannelImpl.java Sat Mar 24 14:43:04 2018 +0900
+++ b/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpMultiChannelImpl.java Sat Mar 24 08:49:55 2018 +0000
@@ -58,7 +58,6 @@
import sun.nio.ch.IOStatus;
import sun.nio.ch.IOUtil;
import sun.nio.ch.Net;
-import sun.nio.ch.PollArrayWrapper;
import sun.nio.ch.SelChImpl;
import sun.nio.ch.SelectionKeyImpl;
import sun.nio.ch.Util;
--- a/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpServerChannelImpl.java Sat Mar 24 14:43:04 2018 +0900
+++ b/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpServerChannelImpl.java Sat Mar 24 08:49:55 2018 +0000
@@ -46,7 +46,6 @@
import sun.nio.ch.IOStatus;
import sun.nio.ch.IOUtil;
import sun.nio.ch.Net;
-import sun.nio.ch.PollArrayWrapper;
import sun.nio.ch.SelChImpl;
import sun.nio.ch.SelectionKeyImpl;
import sun.nio.ch.Util;