|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.nio.ch; |
|
|
|
import java.io.IOException; |
|
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; |
|
import java.nio.channels.spi.SelectorProvider; |
|
import java.util.Collections; |
|
import java.util.HashSet; |
|
import java.util.Iterator; |
|
import java.util.Objects; |
|
import java.util.Set; |
|
import java.util.concurrent.ConcurrentHashMap; |
|
import java.util.function.Consumer; |
|
|
|
|
|
/** |
|
* Base Selector implementation class. |
|
*/ |
|
|
|
abstract class SelectorImpl |
|
extends AbstractSelector |
|
{ |
|
|
|
private final Set<SelectionKey> keys; |
|
|
|
|
|
private final Set<SelectionKey> selectedKeys; |
|
|
|
// Public views of the key sets |
|
private final Set<SelectionKey> publicKeys; |
|
private final Set<SelectionKey> publicSelectedKeys; |
|
|
|
|
|
private boolean inSelect; |
|
|
|
protected SelectorImpl(SelectorProvider sp) { |
|
super(sp); |
|
keys = ConcurrentHashMap.newKeySet(); |
|
selectedKeys = new HashSet<>(); |
|
publicKeys = Collections.unmodifiableSet(keys); |
|
publicSelectedKeys = Util.ungrowableSet(selectedKeys); |
|
} |
|
|
|
private void ensureOpen() { |
|
if (!isOpen()) |
|
throw new ClosedSelectorException(); |
|
} |
|
|
|
@Override |
|
public final Set<SelectionKey> keys() { |
|
ensureOpen(); |
|
return publicKeys; |
|
} |
|
|
|
@Override |
|
public final Set<SelectionKey> selectedKeys() { |
|
ensureOpen(); |
|
return publicSelectedKeys; |
|
} |
|
|
|
|
|
|
|
*/ |
|
protected final void begin(boolean blocking) { |
|
if (blocking) begin(); |
|
} |
|
|
|
|
|
|
|
*/ |
|
protected final void end(boolean blocking) { |
|
if (blocking) end(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected abstract int doSelect(Consumer<SelectionKey> action, long timeout) |
|
throws IOException; |
|
|
|
private int lockAndDoSelect(Consumer<SelectionKey> action, long timeout) |
|
throws IOException |
|
{ |
|
synchronized (this) { |
|
ensureOpen(); |
|
if (inSelect) |
|
throw new IllegalStateException("select in progress"); |
|
inSelect = true; |
|
try { |
|
synchronized (publicSelectedKeys) { |
|
return doSelect(action, timeout); |
|
} |
|
} finally { |
|
inSelect = false; |
|
} |
|
} |
|
} |
|
|
|
@Override |
|
public final int select(long timeout) throws IOException { |
|
if (timeout < 0) |
|
throw new IllegalArgumentException("Negative timeout"); |
|
return lockAndDoSelect(null, (timeout == 0) ? -1 : timeout); |
|
} |
|
|
|
@Override |
|
public final int select() throws IOException { |
|
return lockAndDoSelect(null, -1); |
|
} |
|
|
|
@Override |
|
public final int selectNow() throws IOException { |
|
return lockAndDoSelect(null, 0); |
|
} |
|
|
|
@Override |
|
public final int select(Consumer<SelectionKey> action, long timeout) |
|
throws IOException |
|
{ |
|
Objects.requireNonNull(action); |
|
if (timeout < 0) |
|
throw new IllegalArgumentException("Negative timeout"); |
|
return lockAndDoSelect(action, (timeout == 0) ? -1 : timeout); |
|
} |
|
|
|
@Override |
|
public final int select(Consumer<SelectionKey> action) throws IOException { |
|
Objects.requireNonNull(action); |
|
return lockAndDoSelect(action, -1); |
|
} |
|
|
|
@Override |
|
public final int selectNow(Consumer<SelectionKey> action) throws IOException { |
|
Objects.requireNonNull(action); |
|
return lockAndDoSelect(action, 0); |
|
} |
|
|
|
|
|
|
|
*/ |
|
protected abstract void implClose() throws IOException; |
|
|
|
@Override |
|
public final void implCloseSelector() throws IOException { |
|
wakeup(); |
|
synchronized (this) { |
|
implClose(); |
|
synchronized (publicSelectedKeys) { |
|
|
|
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(); |
|
} |
|
} |
|
} |
|
|
|
@Override |
|
protected final SelectionKey register(AbstractSelectableChannel ch, |
|
int ops, |
|
Object attachment) |
|
{ |
|
if (!(ch instanceof SelChImpl)) |
|
throw new IllegalSelectorException(); |
|
SelectionKeyImpl k = new SelectionKeyImpl((SelChImpl)ch, this); |
|
k.attach(attachment); |
|
|
|
|
|
implRegister(k); |
|
|
|
// add to the selector's key set, removing it immediately if the selector |
|
// is closed. The key is not in the channel's key set at this point but |
|
|
|
keys.add(k); |
|
try { |
|
k.interestOps(ops); |
|
} catch (ClosedSelectorException e) { |
|
assert ch.keyFor(this) == null; |
|
keys.remove(k); |
|
k.cancel(); |
|
throw e; |
|
} |
|
return k; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected void implRegister(SelectionKeyImpl ski) { |
|
ensureOpen(); |
|
} |
|
|
|
|
|
|
|
*/ |
|
protected abstract void implDereg(SelectionKeyImpl ski) throws IOException; |
|
|
|
|
|
|
|
*/ |
|
protected final void processDeregisterQueue() throws IOException { |
|
assert Thread.holdsLock(this); |
|
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(); |
|
i.remove(); |
|
|
|
|
|
implDereg(ski); |
|
|
|
selectedKeys.remove(ski); |
|
keys.remove(ski); |
|
|
|
|
|
deregister(ski); |
|
|
|
SelectableChannel ch = ski.channel(); |
|
if (!ch.isOpen() && !ch.isRegistered()) |
|
((SelChImpl)ch).kill(); |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected final int processReadyEvents(int rOps, |
|
SelectionKeyImpl ski, |
|
Consumer<SelectionKey> action) { |
|
if (action != null) { |
|
ski.translateAndSetReadyOps(rOps); |
|
if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) { |
|
action.accept(ski); |
|
ensureOpen(); |
|
return 1; |
|
} |
|
} else { |
|
assert Thread.holdsLock(publicSelectedKeys); |
|
if (selectedKeys.contains(ski)) { |
|
if (ski.translateAndUpdateReadyOps(rOps)) { |
|
return 1; |
|
} |
|
} else { |
|
ski.translateAndSetReadyOps(rOps); |
|
if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) { |
|
selectedKeys.add(ski); |
|
return 1; |
|
} |
|
} |
|
} |
|
return 0; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
protected abstract void setEventOps(SelectionKeyImpl ski); |
|
} |