8200257: (se) More Selector cleanup

Reviewed-by: bpb
This commit is contained in:
Alan Bateman 2018-03-30 08:28:09 +01:00
parent 8a1bee438c
commit 34c94079ed
20 changed files with 457 additions and 548 deletions

View file

@ -27,15 +27,11 @@ package sun.nio.ch;
import java.io.IOException;
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;
@ -67,14 +63,11 @@ class EPollSelectorImpl extends SelectorImpl {
// maps file descriptor to selection key, synchronize on selector
private final Map<Integer, SelectionKeyImpl> fdToKey = new HashMap<>();
// file descriptors registered with epoll, synchronize on selector
private final BitSet registered = new BitSet();
// pending new registrations/updates, queued by implRegister and putEventOps
// pending new registrations/updates, queued by implRegister and putEventOpos
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<>();
private final Deque<Integer> updateEvents = new ArrayDeque<>();
// interrupt triggering and clearing
private final Object interruptLock = new Object();
@ -113,15 +106,17 @@ class EPollSelectorImpl extends SelectorImpl {
protected int doSelect(long timeout) throws IOException {
assert Thread.holdsLock(this);
// epoll_wait timeout is int
int to = (int) Math.min(timeout, Integer.MAX_VALUE);
boolean blocking = (to != 0);
boolean timedPoll = (to > 0);
int numEntries;
processUpdateQueue();
processDeregisterQueue();
try {
begin();
begin(blocking);
// epoll_wait timeout is int
int to = (int) Math.min(timeout, Integer.MAX_VALUE);
boolean timedPoll = (to > 0);
do {
long startTime = timedPoll ? System.nanoTime() : 0;
numEntries = EPoll.wait(epfd, pollArrayAddress, NUM_EPOLLEVENTS, to);
@ -138,7 +133,7 @@ class EPollSelectorImpl extends SelectorImpl {
assert IOStatus.check(numEntries);
} finally {
end();
end(blocking);
}
processDeregisterQueue();
return updateSelectedKeys(numEntries);
@ -156,33 +151,34 @@ class EPollSelectorImpl extends SelectorImpl {
// new registrations
while ((ski = newKeys.pollFirst()) != null) {
if (ski.isValid()) {
SelChImpl ch = ski.channel;
int fd = ch.getFDVal();
int fd = ski.channel.getFDVal();
SelectionKeyImpl previous = fdToKey.put(fd, ski);
assert previous == null;
assert registered.get(fd) == false;
assert ski.registeredEvents() == 0;
}
}
// changes to interest ops
assert updateKeys.size() == updateOps.size();
assert updateKeys.size() == updateEvents.size();
while ((ski = updateKeys.pollFirst()) != null) {
int ops = updateOps.pollFirst();
int newEvents = updateEvents.pollFirst();
int fd = ski.channel.getFDVal();
if (ski.isValid() && fdToKey.containsKey(fd)) {
if (registered.get(fd)) {
if (ops == 0) {
int registeredEvents = ski.registeredEvents();
if (newEvents != registeredEvents) {
if (newEvents == 0) {
// remove from epoll
EPoll.ctl(epfd, EPOLL_CTL_DEL, fd, 0);
registered.clear(fd);
} else {
// modify events
EPoll.ctl(epfd, EPOLL_CTL_MOD, fd, ops);
if (registeredEvents == 0) {
// add to epoll
EPoll.ctl(epfd, EPOLL_CTL_ADD, fd, newEvents);
} else {
// modify events
EPoll.ctl(epfd, EPOLL_CTL_MOD, fd, newEvents);
}
}
} else if (ops != 0) {
// add to epoll
EPoll.ctl(epfd, EPOLL_CTL_ADD, fd, ops);
registered.set(fd);
ski.registeredEvents(newEvents);
}
}
}
@ -190,8 +186,9 @@ class EPollSelectorImpl extends SelectorImpl {
}
/**
* Update the keys whose fd's have been selected by the epoll.
* Add the ready keys to the ready queue.
* Update the keys of file descriptors that were polled and add them to
* the selected-key set.
* If the interrupt fd has been selected, drain it and clear the interrupt.
*/
private int updateSelectedKeys(int numEntries) throws IOException {
assert Thread.holdsLock(this);
@ -233,7 +230,6 @@ class EPollSelectorImpl extends SelectorImpl {
@Override
protected void implClose() throws IOException {
assert Thread.holdsLock(this);
assert Thread.holdsLock(nioKeys());
// prevent further wakeup
synchronized (interruptLock) {
@ -245,59 +241,37 @@ class EPollSelectorImpl extends SelectorImpl {
FileDispatcherImpl.closeIntFD(fd0);
FileDispatcherImpl.closeIntFD(fd1);
// 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();
}
}
@Override
protected void implRegister(SelectionKeyImpl ski) {
assert Thread.holdsLock(nioKeys());
ensureOpen();
synchronized (updateLock) {
newKeys.addLast(ski);
}
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());
int fd = ski.channel.getFDVal();
fdToKey.remove(fd);
if (registered.get(fd)) {
EPoll.ctl(epfd, EPOLL_CTL_DEL, fd, 0);
registered.clear(fd);
if (fdToKey.remove(fd) != null) {
if (ski.registeredEvents() != 0) {
EPoll.ctl(epfd, EPOLL_CTL_DEL, fd, 0);
ski.registeredEvents(0);
}
} else {
assert ski.registeredEvents() == 0;
}
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) {
public void putEventOps(SelectionKeyImpl ski, int events) {
ensureOpen();
synchronized (updateLock) {
updateOps.addLast(ops); // ops first in case adding the key fails
updateEvents.addLast(events); // events first in case adding key fails
updateKeys.addLast(ski);
}
}

View file

@ -27,15 +27,11 @@ package sun.nio.ch;
import java.io.IOException;
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;
@ -66,15 +62,11 @@ class KQueueSelectorImpl extends SelectorImpl {
// maps file descriptor to selection key, synchronize on selector
private final Map<Integer, SelectionKeyImpl> fdToKey = new HashMap<>();
// file descriptors registered with kqueue, synchronize on selector
private final BitSet registeredReadFilter = new BitSet();
private final BitSet registeredWriteFilter = new BitSet();
// 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<>();
private final Deque<Integer> updateEvents = new ArrayDeque<>();
// interrupt triggering and clearing
private final Object interruptLock = new Object();
@ -113,14 +105,16 @@ class KQueueSelectorImpl extends SelectorImpl {
protected int doSelect(long timeout) throws IOException {
assert Thread.holdsLock(this);
long to = Math.min(timeout, Integer.MAX_VALUE); // max kqueue timeout
boolean blocking = (to != 0);
boolean timedPoll = (to > 0);
int numEntries;
processUpdateQueue();
processDeregisterQueue();
try {
begin();
begin(blocking);
long to = Math.min(timeout, Integer.MAX_VALUE); // max kqueue timeout
boolean timedPoll = (to > 0);
do {
long startTime = timedPoll ? System.nanoTime() : 0;
numEntries = KQueue.poll(kqfd, pollArrayAddress, MAX_KEVENTS, to);
@ -137,7 +131,7 @@ class KQueueSelectorImpl extends SelectorImpl {
assert IOStatus.check(numEntries);
} finally {
end();
end(blocking);
}
processDeregisterQueue();
return updateSelectedKeys(numEntries);
@ -155,41 +149,41 @@ class KQueueSelectorImpl extends SelectorImpl {
// new registrations
while ((ski = newKeys.pollFirst()) != null) {
if (ski.isValid()) {
SelChImpl ch = ski.channel;
int fd = ch.getFDVal();
int fd = ski.channel.getFDVal();
SelectionKeyImpl previous = fdToKey.put(fd, ski);
assert previous == null;
assert registeredReadFilter.get(fd) == false;
assert registeredWriteFilter.get(fd) == false;
assert ski.registeredEvents() == 0;
}
}
// changes to interest ops
assert updateKeys.size() == updateOps.size();
assert updateKeys.size() == updateKeys.size();
while ((ski = updateKeys.pollFirst()) != null) {
int ops = updateOps.pollFirst();
int newEvents = updateEvents.pollFirst();
int fd = ski.channel.getFDVal();
if (ski.isValid() && fdToKey.containsKey(fd)) {
// add or delete interest in read events
if (registeredReadFilter.get(fd)) {
if ((ops & Net.POLLIN) == 0) {
KQueue.register(kqfd, fd, EVFILT_READ, EV_DELETE);
registeredReadFilter.clear(fd);
}
} else if ((ops & Net.POLLIN) != 0) {
KQueue.register(kqfd, fd, EVFILT_READ, EV_ADD);
registeredReadFilter.set(fd);
}
int registeredEvents = ski.registeredEvents();
if (newEvents != registeredEvents) {
// add or delete interest in write events
if (registeredWriteFilter.get(fd)) {
if ((ops & Net.POLLOUT) == 0) {
KQueue.register(kqfd, fd, EVFILT_WRITE, EV_DELETE);
registeredWriteFilter.clear(fd);
// add or delete interest in read events
if ((registeredEvents & Net.POLLIN) != 0) {
if ((newEvents & Net.POLLIN) == 0) {
KQueue.register(kqfd, fd, EVFILT_READ, EV_DELETE);
}
} else if ((newEvents & Net.POLLIN) != 0) {
KQueue.register(kqfd, fd, EVFILT_READ, EV_ADD);
}
} else if ((ops & Net.POLLOUT) != 0) {
KQueue.register(kqfd, fd, EVFILT_WRITE, EV_ADD);
registeredWriteFilter.set(fd);
// add or delete interest in write events
if ((registeredEvents & Net.POLLOUT) != 0) {
if ((newEvents & Net.POLLOUT) == 0) {
KQueue.register(kqfd, fd, EVFILT_WRITE, EV_DELETE);
}
} else if ((newEvents & Net.POLLOUT) != 0) {
KQueue.register(kqfd, fd, EVFILT_WRITE, EV_ADD);
}
ski.registeredEvents(newEvents);
}
}
}
@ -197,8 +191,8 @@ class KQueueSelectorImpl extends SelectorImpl {
}
/**
* Update the keys whose fd's have been selected by kqueue.
* Add the ready keys to the selected key set.
* Update the keys of file descriptors that were polled and add them to
* the selected-key set.
* If the interrupt fd has been selected, drain it and clear the interrupt.
*/
private int updateSelectedKeys(int numEntries) throws IOException {
@ -265,7 +259,6 @@ class KQueueSelectorImpl extends SelectorImpl {
protected void implClose() throws IOException {
assert !isOpen();
assert Thread.holdsLock(this);
assert Thread.holdsLock(nioKeys());
// prevent further wakeup
synchronized (interruptLock) {
@ -277,63 +270,41 @@ class KQueueSelectorImpl extends SelectorImpl {
FileDispatcherImpl.closeIntFD(fd0);
FileDispatcherImpl.closeIntFD(fd1);
// 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();
}
}
@Override
protected void implRegister(SelectionKeyImpl ski) {
assert Thread.holdsLock(nioKeys());
ensureOpen();
synchronized (updateLock) {
newKeys.addLast(ski);
}
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());
int fd = ski.channel.getFDVal();
fdToKey.remove(fd);
if (registeredReadFilter.get(fd)) {
KQueue.register(kqfd, fd, EVFILT_READ, EV_DELETE);
registeredReadFilter.clear(fd);
int registeredEvents = ski.registeredEvents();
if (fdToKey.remove(fd) != null) {
if (registeredEvents != 0) {
if ((registeredEvents & Net.POLLIN) != 0)
KQueue.register(kqfd, fd, EVFILT_READ, EV_DELETE);
if ((registeredEvents & Net.POLLOUT) != 0)
KQueue.register(kqfd, fd, EVFILT_WRITE, EV_DELETE);
ski.registeredEvents(0);
}
} else {
assert registeredEvents == 0;
}
if (registeredWriteFilter.get(fd)) {
KQueue.register(kqfd, fd, EVFILT_WRITE, EV_DELETE);
registeredWriteFilter.clear(fd);
}
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) {
public void putEventOps(SelectionKeyImpl ski, int events) {
ensureOpen();
synchronized (updateLock) {
updateOps.addLast(ops); // ops first in case adding the key fails
updateEvents.addLast(events); // events first in case adding key fails
updateKeys.addLast(ski);
}
}

View file

@ -1229,10 +1229,9 @@ class DatagramChannelImpl
/**
* Translates native poll revent set into a ready operation set
*/
public boolean translateReadyOps(int ops, int initialOps,
SelectionKeyImpl sk) {
int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes
int oldOps = sk.nioReadyOps();
public boolean translateReadyOps(int ops, int initialOps, SelectionKeyImpl ski) {
int intOps = ski.nioInterestOps();
int oldOps = ski.nioReadyOps();
int newOps = initialOps;
if ((ops & Net.POLLNVAL) != 0) {
@ -1244,7 +1243,7 @@ class DatagramChannelImpl
if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
newOps = intOps;
sk.nioReadyOps(newOps);
ski.nioReadyOps(newOps);
return (newOps & ~oldOps) != 0;
}
@ -1256,16 +1255,16 @@ class DatagramChannelImpl
((intOps & SelectionKey.OP_WRITE) != 0))
newOps |= SelectionKey.OP_WRITE;
sk.nioReadyOps(newOps);
ski.nioReadyOps(newOps);
return (newOps & ~oldOps) != 0;
}
public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
return translateReadyOps(ops, sk.nioReadyOps(), sk);
public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl ski) {
return translateReadyOps(ops, ski.nioReadyOps(), ski);
}
public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
return translateReadyOps(ops, 0, sk);
public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl ski) {
return translateReadyOps(ops, 0, ski);
}
/**
@ -1295,16 +1294,15 @@ class DatagramChannelImpl
/**
* Translates an interest operation set into a native poll event set
*/
public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
public int translateInterestOps(int ops) {
int newOps = 0;
if ((ops & SelectionKey.OP_READ) != 0)
newOps |= Net.POLLIN;
if ((ops & SelectionKey.OP_WRITE) != 0)
newOps |= Net.POLLOUT;
if ((ops & SelectionKey.OP_CONNECT) != 0)
newOps |= Net.POLLIN;
sk.selector.putEventOps(sk, newOps);
return newOps;
}
public FileDescriptor getFD() {

View file

@ -61,7 +61,10 @@ public interface SelChImpl extends Channel {
*/
boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk);
void translateAndSetInterestOps(int ops, SelectionKeyImpl sk);
/**
* Translates an interest operation set into a native event set
*/
int translateInterestOps(int ops);
void kill() throws IOException;

View file

@ -39,21 +39,28 @@ import java.nio.channels.spi.AbstractSelectionKey;
public final class SelectionKeyImpl
extends AbstractSelectionKey
{
final SelChImpl channel; // package-private
public final SelectorImpl selector;
// Index for a pollfd array in Selector that this key is registered with
private int index;
private final SelectorImpl selector;
private volatile int interestOps;
private volatile int readyOps;
// registered events in kernel, used by some Selector implementations
private int registeredEvents;
// index of key in pollfd array, used by some Selector implementations
private int index;
SelectionKeyImpl(SelChImpl ch, SelectorImpl sel) {
channel = ch;
selector = sel;
}
private void ensureValid() {
if (!isValid())
throw new CancelledKeyException();
}
@Override
public SelectableChannel channel() {
return (SelectableChannel)channel;
@ -61,20 +68,7 @@ public final class SelectionKeyImpl
@Override
public Selector selector() {
return (Selector)selector;
}
int getIndex() { // package-private
return index;
}
void setIndex(int i) { // package-private
index = i;
}
private void ensureValid() {
if (!isValid())
throw new CancelledKeyException();
return selector;
}
@Override
@ -109,7 +103,7 @@ public final class SelectionKeyImpl
public SelectionKey nioInterestOps(int ops) {
if ((ops & ~channel().validOps()) != 0)
throw new IllegalArgumentException();
channel.translateAndSetInterestOps(ops, this);
selector.putEventOps(this, channel.translateInterestOps(ops));
interestOps = ops;
return this;
}
@ -118,6 +112,24 @@ public final class SelectionKeyImpl
return interestOps;
}
void registeredEvents(int events) {
// assert Thread.holdsLock(selector);
this.registeredEvents = events;
}
int registeredEvents() {
// assert Thread.holdsLock(selector);
return registeredEvents;
}
int getIndex() {
return index;
}
void setIndex(int i) {
index = i;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();

View file

@ -26,9 +26,9 @@
package sun.nio.ch;
import java.io.IOException;
import java.net.SocketException;
import java.nio.channels.ClosedSelectorException;
import java.nio.channels.IllegalSelectorException;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.spi.AbstractSelectableChannel;
import java.nio.channels.spi.AbstractSelector;
@ -47,7 +47,7 @@ public abstract class SelectorImpl
extends AbstractSelector
{
// The set of keys registered with this Selector
protected final HashSet<SelectionKey> keys;
protected final Set<SelectionKey> keys;
// The set of keys with data ready for an operation
protected final Set<SelectionKey> selectedKeys;
@ -88,6 +88,26 @@ public abstract class SelectorImpl
return publicSelectedKeys;
}
/**
* Marks the beginning of a select operation that might block
*/
protected final void begin(boolean blocking) {
if (blocking) begin();
}
/**
* Marks the end of a select operation that may have blocked
*/
protected final void end(boolean blocking) {
if (blocking) end();
}
/**
* Selects the keys for channels that are ready for I/O operations.
*
* @param timeout timeout in milliseconds to wait, 0 to not wait, -1 to
* wait indefinitely
*/
protected abstract int doSelect(long timeout) throws IOException;
private int lockAndDoSelect(long timeout) throws IOException {
@ -125,9 +145,21 @@ public abstract class SelectorImpl
public final void implCloseSelector() throws IOException {
wakeup();
synchronized (this) {
implClose();
synchronized (publicKeys) {
synchronized (publicSelectedKeys) {
implClose();
// 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();
selectedKeys.remove(ski);
i.remove();
}
assert selectedKeys.isEmpty() && keys.isEmpty();
}
}
}
@ -144,8 +176,10 @@ public abstract class SelectorImpl
throw new IllegalSelectorException();
SelectionKeyImpl k = new SelectionKeyImpl((SelChImpl)ch, this);
k.attach(attachment);
// register before adding to key set
implRegister(k);
synchronized (publicKeys) {
implRegister(k);
keys.add(k);
}
k.interestOps(ops);
return k;
@ -156,27 +190,37 @@ public abstract class SelectorImpl
protected abstract void implDereg(SelectionKeyImpl ski) throws IOException;
protected final void processDeregisterQueue() throws IOException {
// Precondition: Synchronized on this, keys, and selectedKeys
assert Thread.holdsLock(this);
assert Thread.holdsLock(publicKeys);
assert Thread.holdsLock(publicSelectedKeys);
Set<SelectionKey> cks = cancelledKeys();
synchronized (cks) {
if (!cks.isEmpty()) {
Iterator<SelectionKey> i = cks.iterator();
while (i.hasNext()) {
SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
try {
implDereg(ski);
} catch (SocketException se) {
throw new IOException("Error deregistering key", se);
} finally {
i.remove();
}
i.remove();
// remove the key from the selector
implDereg(ski);
selectedKeys.remove(ski);
keys.remove(ski);
// remove from channel's key set
deregister(ski);
SelectableChannel ch = ski.channel();
if (!ch.isOpen() && !ch.isRegistered())
((SelChImpl)ch).kill();
}
}
}
}
/**
* Invoked to change the key's interest set
* Change the event set in the selector
*/
public abstract void putEventOps(SelectionKeyImpl ski, int ops);
protected abstract void putEventOps(SelectionKeyImpl ski, int events);
}

View file

@ -445,10 +445,9 @@ class ServerSocketChannelImpl
/**
* Translates native poll revent set into a ready operation set
*/
public boolean translateReadyOps(int ops, int initialOps,
SelectionKeyImpl sk) {
int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes
int oldOps = sk.nioReadyOps();
public boolean translateReadyOps(int ops, int initialOps, SelectionKeyImpl ski) {
int intOps = ski.nioInterestOps();
int oldOps = ski.nioReadyOps();
int newOps = initialOps;
if ((ops & Net.POLLNVAL) != 0) {
@ -460,7 +459,7 @@ class ServerSocketChannelImpl
if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
newOps = intOps;
sk.nioReadyOps(newOps);
ski.nioReadyOps(newOps);
return (newOps & ~oldOps) != 0;
}
@ -468,29 +467,26 @@ class ServerSocketChannelImpl
((intOps & SelectionKey.OP_ACCEPT) != 0))
newOps |= SelectionKey.OP_ACCEPT;
sk.nioReadyOps(newOps);
ski.nioReadyOps(newOps);
return (newOps & ~oldOps) != 0;
}
public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
return translateReadyOps(ops, sk.nioReadyOps(), sk);
public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl ski) {
return translateReadyOps(ops, ski.nioReadyOps(), ski);
}
public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
return translateReadyOps(ops, 0, sk);
public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl ski) {
return translateReadyOps(ops, 0, ski);
}
/**
* Translates an interest operation set into a native poll event set
*/
public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
public int translateInterestOps(int ops) {
int newOps = 0;
// Translate ops
if ((ops & SelectionKey.OP_ACCEPT) != 0)
newOps |= Net.POLLIN;
// Place ops into pollfd array
sk.selector.putEventOps(sk, newOps);
return newOps;
}
public FileDescriptor getFD() {

View file

@ -994,10 +994,9 @@ class SocketChannelImpl
/**
* Translates native poll revent ops into a ready operation ops
*/
public boolean translateReadyOps(int ops, int initialOps,
SelectionKeyImpl sk) {
int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes
int oldOps = sk.nioReadyOps();
public boolean translateReadyOps(int ops, int initialOps, SelectionKeyImpl ski) {
int intOps = ski.nioInterestOps();
int oldOps = ski.nioReadyOps();
int newOps = initialOps;
if ((ops & Net.POLLNVAL) != 0) {
@ -1009,7 +1008,7 @@ class SocketChannelImpl
if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
newOps = intOps;
sk.nioReadyOps(newOps);
ski.nioReadyOps(newOps);
return (newOps & ~oldOps) != 0;
}
@ -1026,22 +1025,22 @@ class SocketChannelImpl
((intOps & SelectionKey.OP_WRITE) != 0) && connected)
newOps |= SelectionKey.OP_WRITE;
sk.nioReadyOps(newOps);
ski.nioReadyOps(newOps);
return (newOps & ~oldOps) != 0;
}
public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
return translateReadyOps(ops, sk.nioReadyOps(), sk);
public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl ski) {
return translateReadyOps(ops, ski.nioReadyOps(), ski);
}
public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
return translateReadyOps(ops, 0, sk);
public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl ski) {
return translateReadyOps(ops, 0, ski);
}
/**
* Translates an interest operation set into a native poll event set
*/
public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
public int translateInterestOps(int ops) {
int newOps = 0;
if ((ops & SelectionKey.OP_READ) != 0)
newOps |= Net.POLLIN;
@ -1049,7 +1048,7 @@ class SocketChannelImpl
newOps |= Net.POLLOUT;
if ((ops & SelectionKey.OP_CONNECT) != 0)
newOps |= Net.POLLCONN;
sk.selector.putEventOps(sk, newOps);
return newOps;
}
public FileDescriptor getFD() {

View file

@ -27,15 +27,11 @@ package sun.nio.ch;
import java.io.IOException;
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;
@ -59,14 +55,11 @@ class DevPollSelectorImpl
// maps file descriptor to selection key, synchronize on selector
private final Map<Integer, SelectionKeyImpl> fdToKey = new HashMap<>();
// file descriptors registered with /dev/poll, synchronize on selector
private final BitSet registered = new BitSet();
// 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<>();
private final Deque<Integer> updateEvents = new ArrayDeque<>();
// interrupt triggering and clearing
private final Object interruptLock = new Object();
@ -99,15 +92,16 @@ class DevPollSelectorImpl
throws IOException
{
assert Thread.holdsLock(this);
boolean blocking = (timeout != 0);
int numEntries;
processUpdateQueue();
processDeregisterQueue();
try {
begin();
begin(blocking);
numEntries = pollWrapper.poll(timeout);
} finally {
end();
end(blocking);
}
processDeregisterQueue();
return updateSelectedKeys(numEntries);
@ -125,41 +119,35 @@ class DevPollSelectorImpl
// new registrations
while ((ski = newKeys.pollFirst()) != null) {
if (ski.isValid()) {
SelChImpl ch = ski.channel;
int fd = ch.getFDVal();
int fd = ski.channel.getFDVal();
SelectionKeyImpl previous = fdToKey.put(fd, ski);
assert previous == null;
assert registered.get(fd) == false;
assert ski.registeredEvents() == 0;
}
}
// 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();
assert updateKeys.size() == updateEvents.size();
int index = 0;
while ((ski = updateKeys.pollFirst()) != null) {
int ops = updateOps.pollFirst();
int newEvents = updateEvents.pollFirst();
int fd = ski.channel.getFDVal();
if (ski.isValid() && fdToKey.containsKey(fd)) {
if (registered.get(fd)) {
if (ops == 0) {
// remove file descriptor
int registeredEvents = ski.registeredEvents();
if (newEvents != registeredEvents) {
if (registeredEvents != 0)
pollWrapper.putPollFD(index++, fd, POLLREMOVE);
registered.clear(fd);
} else {
// change events
pollWrapper.putPollFD(index++, fd, POLLREMOVE);
pollWrapper.putPollFD(index++, fd, (short)ops);
if (newEvents != 0)
pollWrapper.putPollFD(index++, fd, (short)newEvents);
ski.registeredEvents(newEvents);
// write to /dev/poll
if (index > (NUM_POLLFDS-2)) {
pollWrapper.registerMultiple(index);
index = 0;
}
} 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;
}
}
}
@ -171,8 +159,9 @@ class DevPollSelectorImpl
}
/**
* Update the keys whose fd's have been selected by the /dev/poll.
* Add the ready keys to the ready queue.
* Update the keys of file descriptors that were polled and add them to
* the selected-key set.
* If the interrupt fd has been selected, drain it and clear the interrupt.
*/
private int updateSelectedKeys(int numEntries) throws IOException {
assert Thread.holdsLock(this);
@ -214,7 +203,6 @@ class DevPollSelectorImpl
protected void implClose() throws IOException {
assert !isOpen();
assert Thread.holdsLock(this);
assert Thread.holdsLock(nioKeys());
// prevent further wakeup
synchronized (interruptLock) {
@ -224,59 +212,37 @@ class DevPollSelectorImpl
pollWrapper.close();
FileDispatcherImpl.closeIntFD(fd0);
FileDispatcherImpl.closeIntFD(fd1);
// 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();
}
}
@Override
protected void implRegister(SelectionKeyImpl ski) {
assert Thread.holdsLock(nioKeys());
ensureOpen();
synchronized (updateLock) {
newKeys.addLast(ski);
}
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());
int fd = ski.channel.getFDVal();
fdToKey.remove(fd);
if (registered.get(fd)) {
pollWrapper.register(fd, POLLREMOVE);
registered.clear(fd);
if (fdToKey.remove(fd) != null) {
if (ski.registeredEvents() != 0) {
pollWrapper.register(fd, POLLREMOVE);
ski.registeredEvents(0);
}
} else {
assert ski.registeredEvents() == 0;
}
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) {
public void putEventOps(SelectionKeyImpl ski, int events) {
ensureOpen();
synchronized (updateLock) {
updateOps.addLast(ops); // ops first in case adding the key fails
updateEvents.addLast(events); // events first in case adding key fails
updateKeys.addLast(ski);
}
}

View file

@ -27,17 +27,14 @@ package sun.nio.ch;
import java.io.IOException;
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;
@ -69,18 +66,8 @@ class EventPortSelectorImpl
private final long pollArrayAddress;
private final AllocatedNativeObject pollArray;
// 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;
}
}
// maps a file descriptor to registration entry, synchronize on selector
private final Map<Integer, RegEntry> fdToRegEntry = new HashMap<>();
// maps file descriptor to selection key, synchronize on selector
private final Map<Integer, SelectionKeyImpl> fdToKey = new HashMap<>();
// the last update operation, incremented by processUpdateQueue
private int lastUpdate;
@ -90,7 +77,7 @@ class EventPortSelectorImpl
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<>();
private final Deque<Integer> updateEvents = new ArrayDeque<>();
// interrupt triggering and clearing
private final Object interruptLock = new Object();
@ -115,14 +102,16 @@ class EventPortSelectorImpl
protected int doSelect(long timeout) throws IOException {
assert Thread.holdsLock(this);
long to = timeout;
boolean blocking = (to != 0);
boolean timedPoll = (to > 0);
int numEvents;
processUpdateQueue();
processDeregisterQueue();
try {
begin();
begin(blocking);
long to = timeout;
boolean timedPoll = (to > 0);
do {
long startTime = timedPoll ? System.nanoTime() : 0;
numEvents = port_getn(pfd, pollArrayAddress, MAX_EVENTS, to);
@ -139,7 +128,7 @@ class EventPortSelectorImpl
assert IOStatus.check(numEvents);
} finally {
end();
end(blocking);
}
processDeregisterQueue();
return processPortEvents(numEvents);
@ -161,30 +150,27 @@ class EventPortSelectorImpl
// 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));
int fd = ski.channel.getFDVal();
SelectionKeyImpl previous = fdToKey.put(fd, ski);
assert previous == null;
assert ski.registeredEvents() == 0;
}
}
// changes to interest ops
assert updateKeys.size() == updateOps.size();
assert updateKeys.size() == updateEvents.size();
while ((ski = updateKeys.pollFirst()) != null) {
int ops = updateOps.pollFirst();
int newEvents = updateEvents.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) {
if (ski.isValid() && fdToKey.containsKey(fd)) {
if (newEvents != ski.registeredEvents()) {
if (newEvents == 0) {
port_dissociate(pfd, PORT_SOURCE_FD, fd);
} else {
port_associate(pfd, PORT_SOURCE_FD, fd, ops);
port_associate(pfd, PORT_SOURCE_FD, fd, newEvents);
}
e.registeredOps = ops;
ski.registeredEvents(newEvents);
}
e.lastUpdate = lastUpdate;
}
}
}
@ -209,9 +195,8 @@ class EventPortSelectorImpl
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;
SelectionKeyImpl ski = fdToKey.get(fd);
if (ski != null) {
int rOps = getEventOps(i);
if (selectedKeys.contains(ski)) {
if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
@ -225,12 +210,11 @@ class EventPortSelectorImpl
}
}
// 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;
// re-queue key to head so that it is re-associated at
// next select (and before other changes)
updateEvents.addFirst(ski.registeredEvents());
updateKeys.addFirst(ski);
ski.registeredEvents(0);
}
} else if (source == PORT_SOURCE_USER) {
interrupted = true;
@ -250,7 +234,6 @@ class EventPortSelectorImpl
protected void implClose() throws IOException {
assert !isOpen();
assert Thread.holdsLock(this);
assert Thread.holdsLock(nioKeys());
// prevent further wakeup
synchronized (interruptLock) {
@ -259,61 +242,38 @@ class EventPortSelectorImpl
port_close(pfd);
pollArray.free();
// 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();
}
}
@Override
protected void implRegister(SelectionKeyImpl ski) {
assert Thread.holdsLock(nioKeys());
ensureOpen();
synchronized (updateLock) {
newKeys.addLast(ski);
}
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());
int fd = ski.channel.getFDVal();
RegEntry e = fdToRegEntry.remove(fd);
if (e != null && e.registeredOps != 0) {
port_dissociate(pfd, PORT_SOURCE_FD, fd);
if (fdToKey.remove(fd) != null) {
if (ski.registeredEvents() != 0) {
port_dissociate(pfd, PORT_SOURCE_FD, fd);
ski.registeredEvents(0);
}
} else {
assert ski.registeredEvents() == 0;
}
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) {
public void putEventOps(SelectionKeyImpl ski, int events) {
ensureOpen();
synchronized (updateLock) {
// push to front of deque so that it processed before other
// updates for the same key.
updateOps.addFirst(ops);
updateKeys.addFirst(ski);
updateEvents.addLast(events); // events first in case adding key fails
updateKeys.addLast(ski);
}
}

View file

@ -26,14 +26,11 @@ package sun.nio.ch;
import java.io.IOException;
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;
@ -63,7 +60,7 @@ class PollSelectorImpl extends SelectorImpl {
// 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<>();
private final Deque<Integer> updateEvents = new ArrayDeque<>();
// interrupt triggering and clearing
private final Object interruptLock = new Object();
@ -99,13 +96,15 @@ class PollSelectorImpl extends SelectorImpl {
protected int doSelect(long timeout) throws IOException {
assert Thread.holdsLock(this);
int to = (int) Math.min(timeout, Integer.MAX_VALUE); // max poll timeout
boolean blocking = (to != 0);
boolean timedPoll = (to > 0);
processUpdateQueue();
processDeregisterQueue();
try {
begin();
begin(blocking);
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;
@ -123,7 +122,7 @@ class PollSelectorImpl extends SelectorImpl {
assert numPolled <= pollArraySize;
} finally {
end();
end(blocking);
}
processDeregisterQueue();
@ -137,23 +136,22 @@ class PollSelectorImpl extends SelectorImpl {
assert Thread.holdsLock(this);
synchronized (updateLock) {
assert updateKeys.size() == updateOps.size();
assert updateKeys.size() == updateEvents.size();
SelectionKeyImpl ski;
while ((ski = updateKeys.pollFirst()) != null) {
int ops = updateOps.pollFirst();
int newEvents = updateEvents.pollFirst();
if (ski.isValid()) {
int index = ski.getIndex();
assert index >= 0 && index < pollArraySize;
if (index > 0) {
assert pollKeys.get(index) == ski;
if (ops == 0) {
if (newEvents == 0) {
remove(ski);
} else {
update(ski, ops);
update(ski, newEvents);
}
} else if (ops != 0) {
add(ski, ops);
} else if (newEvents != 0) {
add(ski, newEvents);
}
}
}
@ -161,8 +159,8 @@ class PollSelectorImpl extends SelectorImpl {
}
/**
* Update the keys whose fd's have been selected by kqueue.
* Add the ready keys to the selected key set.
* Update the keys of file descriptors that were polled and add them to
* the selected-key set.
* If the interrupt fd has been selected, drain it and clear the interrupt.
*/
private int updateSelectedKeys() throws IOException {
@ -205,7 +203,6 @@ class PollSelectorImpl extends SelectorImpl {
protected void implClose() throws IOException {
assert !isOpen();
assert Thread.holdsLock(this);
assert Thread.holdsLock(nioKeys());
// prevent further wakeup
synchronized (interruptLock) {
@ -215,59 +212,31 @@ class PollSelectorImpl extends SelectorImpl {
pollArray.free();
FileDispatcherImpl.closeIntFD(fd0);
FileDispatcherImpl.closeIntFD(fd1);
// 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) {
public void putEventOps(SelectionKeyImpl ski, int events) {
ensureOpen();
synchronized (updateLock) {
updateOps.addLast(ops); // ops first in case adding the key fails
updateEvents.addLast(events); // events first in case adding key fails
updateKeys.addLast(ski);
}
}

View file

@ -164,10 +164,9 @@ class SinkChannelImpl
}
}
public boolean translateReadyOps(int ops, int initialOps,
SelectionKeyImpl sk) {
int intOps = sk.nioInterestOps();// Do this just once, it synchronizes
int oldOps = sk.nioReadyOps();
public boolean translateReadyOps(int ops, int initialOps, SelectionKeyImpl ski) {
int intOps = ski.nioInterestOps();
int oldOps = ski.nioReadyOps();
int newOps = initialOps;
if ((ops & Net.POLLNVAL) != 0)
@ -175,7 +174,7 @@ class SinkChannelImpl
if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
newOps = intOps;
sk.nioReadyOps(newOps);
ski.nioReadyOps(newOps);
return (newOps & ~oldOps) != 0;
}
@ -183,22 +182,23 @@ class SinkChannelImpl
((intOps & SelectionKey.OP_WRITE) != 0))
newOps |= SelectionKey.OP_WRITE;
sk.nioReadyOps(newOps);
ski.nioReadyOps(newOps);
return (newOps & ~oldOps) != 0;
}
public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
return translateReadyOps(ops, sk.nioReadyOps(), sk);
public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl ski) {
return translateReadyOps(ops, ski.nioReadyOps(), ski);
}
public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
return translateReadyOps(ops, 0, sk);
public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl ski) {
return translateReadyOps(ops, 0, ski);
}
public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
public int translateInterestOps(int ops) {
int newOps = 0;
if (ops == SelectionKey.OP_WRITE)
ops = Net.POLLOUT;
sk.selector.putEventOps(sk, ops);
newOps |= Net.POLLOUT;
return newOps;
}
/**

View file

@ -164,10 +164,9 @@ class SourceChannelImpl
}
}
public boolean translateReadyOps(int ops, int initialOps,
SelectionKeyImpl sk) {
int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes
int oldOps = sk.nioReadyOps();
public boolean translateReadyOps(int ops, int initialOps, SelectionKeyImpl ski) {
int intOps = ski.nioInterestOps();
int oldOps = ski.nioReadyOps();
int newOps = initialOps;
if ((ops & Net.POLLNVAL) != 0)
@ -175,7 +174,7 @@ class SourceChannelImpl
if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
newOps = intOps;
sk.nioReadyOps(newOps);
ski.nioReadyOps(newOps);
return (newOps & ~oldOps) != 0;
}
@ -183,22 +182,23 @@ class SourceChannelImpl
((intOps & SelectionKey.OP_READ) != 0))
newOps |= SelectionKey.OP_READ;
sk.nioReadyOps(newOps);
ski.nioReadyOps(newOps);
return (newOps & ~oldOps) != 0;
}
public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
return translateReadyOps(ops, sk.nioReadyOps(), sk);
public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl ski) {
return translateReadyOps(ops, ski.nioReadyOps(), ski);
}
public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
return translateReadyOps(ops, 0, sk);
public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl ski) {
return translateReadyOps(ops, 0, ski);
}
public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
public int translateInterestOps(int ops) {
int newOps = 0;
if (ops == SelectionKey.OP_READ)
ops = Net.POLLIN;
sk.selector.putEventOps(sk, ops);
newOps |= Net.POLLIN;
return newOps;
}
/**

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
* 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
@ -63,8 +63,9 @@ class PollArrayWrapper {
}
// Prepare another pollfd struct for use.
void addEntry(int index, SelectionKeyImpl ski) {
void putEntry(int index, SelectionKeyImpl ski) {
putDescriptor(index, ski.channel.getFDVal());
putEventOps(index, 0);
}
// Writes the pollfd entry from the source wrapper at the source index

View file

@ -72,10 +72,9 @@ class SinkChannelImpl
sc.configureBlocking(block);
}
public boolean translateReadyOps(int ops, int initialOps,
SelectionKeyImpl sk) {
int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes
int oldOps = sk.nioReadyOps();
public boolean translateReadyOps(int ops, int initialOps, SelectionKeyImpl ski) {
int intOps = ski.nioInterestOps();
int oldOps = ski.nioReadyOps();
int newOps = initialOps;
if ((ops & Net.POLLNVAL) != 0)
@ -83,7 +82,7 @@ class SinkChannelImpl
if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
newOps = intOps;
sk.nioReadyOps(newOps);
ski.nioReadyOps(newOps);
return (newOps & ~oldOps) != 0;
}
@ -91,22 +90,23 @@ class SinkChannelImpl
((intOps & SelectionKey.OP_WRITE) != 0))
newOps |= SelectionKey.OP_WRITE;
sk.nioReadyOps(newOps);
ski.nioReadyOps(newOps);
return (newOps & ~oldOps) != 0;
}
public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
return translateReadyOps(ops, sk.nioReadyOps(), sk);
public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl ski) {
return translateReadyOps(ops, ski.nioReadyOps(), ski);
}
public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
return translateReadyOps(ops, 0, sk);
public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl ski) {
return translateReadyOps(ops, 0, ski);
}
public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
public int translateInterestOps(int ops) {
int newOps = 0;
if ((ops & SelectionKey.OP_WRITE) != 0)
ops = Net.POLLOUT;
sk.selector.putEventOps(sk, ops);
newOps |= Net.POLLOUT;
return newOps;
}
public int write(ByteBuffer src) throws IOException {

View file

@ -71,10 +71,9 @@ class SourceChannelImpl
sc.configureBlocking(block);
}
public boolean translateReadyOps(int ops, int initialOps,
SelectionKeyImpl sk) {
int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes
int oldOps = sk.nioReadyOps();
public boolean translateReadyOps(int ops, int initialOps, SelectionKeyImpl ski) {
int intOps = ski.nioInterestOps();
int oldOps = ski.nioReadyOps();
int newOps = initialOps;
if ((ops & Net.POLLNVAL) != 0)
@ -82,7 +81,7 @@ class SourceChannelImpl
if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
newOps = intOps;
sk.nioReadyOps(newOps);
ski.nioReadyOps(newOps);
return (newOps & ~oldOps) != 0;
}
@ -90,22 +89,23 @@ class SourceChannelImpl
((intOps & SelectionKey.OP_READ) != 0))
newOps |= SelectionKey.OP_READ;
sk.nioReadyOps(newOps);
ski.nioReadyOps(newOps);
return (newOps & ~oldOps) != 0;
}
public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
return translateReadyOps(ops, sk.nioReadyOps(), sk);
public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl ski) {
return translateReadyOps(ops, ski.nioReadyOps(), ski);
}
public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
return translateReadyOps(ops, 0, sk);
public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl ski) {
return translateReadyOps(ops, 0, ski);
}
public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
public int translateInterestOps(int ops) {
int newOps = 0;
if ((ops & SelectionKey.OP_READ) != 0)
ops = Net.POLLIN;
sk.selector.putEventOps(sk, ops);
newOps |= Net.POLLIN;
return newOps;
}
public int read(ByteBuffer dst) throws IOException {

View file

@ -23,23 +23,19 @@
* questions.
*/
/*
*/
package sun.nio.ch;
import java.nio.channels.spi.SelectorProvider;
import java.nio.channels.Selector;
import java.io.IOException;
import java.nio.channels.ClosedSelectorException;
import java.nio.channels.Pipe;
import java.nio.channels.SelectableChannel;
import java.io.IOException;
import java.nio.channels.CancelledKeyException;
import java.util.List;
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.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* A multi-threaded implementation of Selector for Windows.
@ -80,9 +76,6 @@ class WindowsSelectorImpl extends SelectorImpl {
// File descriptors corresponding to source and sink
private final int wakeupSourceFd, wakeupSinkFd;
// Lock for close cleanup
private final Object closeLock = new Object();
// Maps file descriptors to their indices in pollArray
private static final class FdMap extends HashMap<Integer, MapEntry> {
static final long serialVersionUID = 0L;
@ -103,7 +96,7 @@ class WindowsSelectorImpl extends SelectorImpl {
// class for fdMap entries
private static final class MapEntry {
SelectionKeyImpl ski;
final SelectionKeyImpl ski;
long updateCount = 0;
long clearedCount = 0;
MapEntry(SelectionKeyImpl ski) {
@ -121,6 +114,13 @@ class WindowsSelectorImpl extends SelectorImpl {
private final Object interruptLock = new Object();
private volatile boolean interruptTriggered;
// 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> updateEvents = new ArrayDeque<>();
WindowsSelectorImpl(SelectorProvider sp) throws IOException {
super(sp);
pollWrapper = new PollArrayWrapper(INIT_CAP);
@ -135,11 +135,16 @@ class WindowsSelectorImpl extends SelectorImpl {
pollWrapper.addWakeupSocket(wakeupSourceFd, 0);
}
private void ensureOpen() {
if (!isOpen())
throw new ClosedSelectorException();
}
@Override
protected int doSelect(long timeout) throws IOException {
if (channelArray == null)
throw new ClosedSelectorException();
assert Thread.holdsLock(this);
this.timeout = timeout; // set selector timeout
processUpdateQueue();
processDeregisterQueue();
if (interruptTriggered) {
resetWakeupSocket();
@ -176,6 +181,42 @@ class WindowsSelectorImpl extends SelectorImpl {
return updated;
}
/**
* Process new registrations and changes to the interest ops.
*/
private void processUpdateQueue() {
assert Thread.holdsLock(this);
synchronized (updateLock) {
SelectionKeyImpl ski;
// new registrations
while ((ski = newKeys.pollFirst()) != null) {
if (ski.isValid()) {
growIfNeeded();
channelArray[totalChannels] = ski;
ski.setIndex(totalChannels);
pollWrapper.putEntry(totalChannels, ski);
totalChannels++;
MapEntry previous = fdMap.put(ski);
assert previous == null;
}
}
// changes to interest ops
assert updateKeys.size() == updateEvents.size();
while ((ski = updateKeys.pollFirst()) != null) {
int events = updateEvents.pollFirst();
int fd = ski.channel.getFDVal();
if (ski.isValid() && fdMap.containsKey(fd)) {
int index = ski.getIndex();
assert index >= 0 && index < totalChannels;
pollWrapper.putEventOps(index, events);
}
}
}
}
// Helper threads wait on this lock for the next poll.
private final StartLock startLock = new StartLock();
@ -503,46 +544,29 @@ class WindowsSelectorImpl extends SelectorImpl {
@Override
protected void implClose() throws IOException {
synchronized (closeLock) {
if (channelArray != null) {
if (pollWrapper != null) {
// prevent further wakeup
synchronized (interruptLock) {
interruptTriggered = true;
}
wakeupPipe.sink().close();
wakeupPipe.source().close();
for(int i = 1; i < totalChannels; i++) { // Deregister channels
if (i % MAX_SELECTABLE_FDS != 0) { // skip wakeupEvent
deregister(channelArray[i]);
SelectableChannel selch = channelArray[i].channel();
if (!selch.isOpen() && !selch.isRegistered())
((SelChImpl)selch).kill();
}
}
pollWrapper.free();
pollWrapper = null;
channelArray = null;
// Make all remaining helper threads exit
for (SelectThread t: threads)
t.makeZombie();
startLock.startThreads();
}
}
assert !isOpen();
assert Thread.holdsLock(this);
// prevent further wakeup
synchronized (interruptLock) {
interruptTriggered = true;
}
wakeupPipe.sink().close();
wakeupPipe.source().close();
pollWrapper.free();
// Make all remaining helper threads exit
for (SelectThread t: threads)
t.makeZombie();
startLock.startThreads();
}
@Override
protected void implRegister(SelectionKeyImpl ski) {
synchronized (closeLock) {
if (pollWrapper == null)
throw new ClosedSelectorException();
growIfNeeded();
channelArray[totalChannels] = ski;
ski.setIndex(totalChannels);
fdMap.put(ski);
keys.add(ski);
pollWrapper.addEntry(totalChannels, ski);
totalChannels++;
ensureOpen();
synchronized (updateLock) {
newKeys.addLast(ski);
}
}
@ -561,47 +585,43 @@ class WindowsSelectorImpl extends SelectorImpl {
}
}
protected void implDereg(SelectionKeyImpl ski) throws IOException{
int i = ski.getIndex();
assert (i >= 0);
synchronized (closeLock) {
@Override
protected void implDereg(SelectionKeyImpl ski) {
assert !ski.isValid();
assert Thread.holdsLock(this);
if (fdMap.remove(ski) != null) {
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.replaceEntry(pollWrapper, totalChannels - 1,
pollWrapper, i);
pollWrapper.replaceEntry(pollWrapper, totalChannels-1, pollWrapper, i);
}
ski.setIndex(-1);
}
channelArray[totalChannels - 1] = null;
totalChannels--;
if ( totalChannels != 1 && totalChannels % MAX_SELECTABLE_FDS == 1) {
channelArray[totalChannels - 1] = null;
totalChannels--;
threadsCount--; // The last thread has become redundant.
}
fdMap.remove(ski); // Remove the key from fdMap, keys and selectedKeys
keys.remove(ski);
selectedKeys.remove(ski);
deregister(ski);
SelectableChannel selch = ski.channel();
if (!selch.isOpen() && !selch.isRegistered())
((SelChImpl)selch).kill();
}
public void putEventOps(SelectionKeyImpl sk, int ops) {
synchronized (closeLock) {
if (pollWrapper == null)
throw new ClosedSelectorException();
// make sure this sk has not been removed yet
int index = sk.getIndex();
if (index == -1)
throw new CancelledKeyException();
pollWrapper.putEventOps(index, ops);
if (totalChannels != 1 && totalChannels % MAX_SELECTABLE_FDS == 1) {
totalChannels--;
threadsCount--; // The last thread has become redundant.
}
}
}
@Override
public void putEventOps(SelectionKeyImpl ski, int events) {
ensureOpen();
synchronized (updateLock) {
updateEvents.addLast(events); // events first in case adding key fails
updateKeys.addLast(ski);
}
}
@Override
public Selector wakeup() {
synchronized (interruptLock) {
if (!interruptTriggered) {

View file

@ -641,7 +641,7 @@ public class SctpChannelImpl extends SctpChannel
}
@Override
public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
public int translateInterestOps(int ops) {
int newOps = 0;
if ((ops & SelectionKey.OP_READ) != 0)
newOps |= Net.POLLIN;
@ -649,7 +649,7 @@ public class SctpChannelImpl extends SctpChannel
newOps |= Net.POLLOUT;
if ((ops & SelectionKey.OP_CONNECT) != 0)
newOps |= Net.POLLCONN;
sk.selector.putEventOps(sk, newOps);
return newOps;
}
@Override

View file

@ -356,13 +356,13 @@ public class SctpMultiChannelImpl extends SctpMultiChannel
}
@Override
public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
public int translateInterestOps(int ops) {
int newOps = 0;
if ((ops & SelectionKey.OP_READ) != 0)
newOps |= Net.POLLIN;
if ((ops & SelectionKey.OP_WRITE) != 0)
newOps |= Net.POLLOUT;
sk.selector.putEventOps(sk, newOps);
return newOps;
}
@Override

View file

@ -345,15 +345,11 @@ public class SctpServerChannelImpl extends SctpServerChannel
}
@Override
public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
public int translateInterestOps(int ops) {
int newOps = 0;
/* Translate ops */
if ((ops & SelectionKey.OP_ACCEPT) != 0)
newOps |= Net.POLLIN;
/* Place ops into pollfd array */
sk.selector.putEventOps(sk, newOps);
return newOps;
}
@Override