META-INF.modules.java.base.classes.sun.nio.ch.SelectorImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of java.base Show documentation
Show all versions of java.base Show documentation
Bytecoder java.base Module
/*
* Copyright (c) 2000, 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.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
{
// The set of keys registered with this Selector
private final Set keys;
// The set of keys with data ready for an operation
private final Set selectedKeys;
// Public views of the key sets
private final Set publicKeys; // Immutable
private final Set publicSelectedKeys; // Removal allowed, but not addition
// used to check for reentrancy
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 keys() {
ensureOpen();
return publicKeys;
}
@Override
public final Set selectedKeys() {
ensureOpen();
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 action the action to perform, can be null
* @param timeout timeout in milliseconds to wait, 0 to not wait, -1 to
* wait indefinitely
*/
protected abstract int doSelect(Consumer action, long timeout)
throws IOException;
private int lockAndDoSelect(Consumer 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 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 action) throws IOException {
Objects.requireNonNull(action);
return lockAndDoSelect(action, -1);
}
@Override
public final int selectNow(Consumer action) throws IOException {
Objects.requireNonNull(action);
return lockAndDoSelect(action, 0);
}
/**
* Invoked by implCloseSelector to close the selector.
*/
protected abstract void implClose() throws IOException;
@Override
public final void implCloseSelector() throws IOException {
wakeup();
synchronized (this) {
implClose();
synchronized (publicSelectedKeys) {
// Deregister channels
Iterator 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);
// register (if needed) before adding to key set
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
// it may be observed by a thread iterating over the selector's key set.
keys.add(k);
try {
k.interestOps(ops);
} catch (ClosedSelectorException e) {
assert ch.keyFor(this) == null;
keys.remove(k);
k.cancel();
throw e;
}
return k;
}
/**
* Register the key in the selector.
*
* The default implementation checks if the selector is open. It should
* be overridden by selector implementations as needed.
*/
protected void implRegister(SelectionKeyImpl ski) {
ensureOpen();
}
/**
* Removes the key from the selector
*/
protected abstract void implDereg(SelectionKeyImpl ski) throws IOException;
/**
* Invoked by selection operations to process the cancelled-key set
*/
protected final void processDeregisterQueue() throws IOException {
assert Thread.holdsLock(this);
assert Thread.holdsLock(publicSelectedKeys);
Set cks = cancelledKeys();
synchronized (cks) {
if (!cks.isEmpty()) {
Iterator i = cks.iterator();
while (i.hasNext()) {
SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
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 by selection operations to handle ready events. If an action
* is specified then it is invoked to handle the key, otherwise the key
* is added to the selected-key set (or updated when it is already in the
* set).
*/
protected final int processReadyEvents(int rOps,
SelectionKeyImpl ski,
Consumer 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;
}
/**
* Invoked by interestOps to ensure the interest ops are updated at the
* next selection operation.
*/
protected abstract void setEventOps(SelectionKeyImpl ski);
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy