Path: blob/master/src/java.base/share/classes/sun/nio/ch/SelectorImpl.java
41159 views
/*1* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.nio.ch;2627import java.io.IOException;28import java.nio.channels.ClosedSelectorException;29import java.nio.channels.IllegalSelectorException;30import java.nio.channels.SelectableChannel;31import java.nio.channels.SelectionKey;32import java.nio.channels.spi.AbstractSelectableChannel;33import java.nio.channels.spi.AbstractSelector;34import java.nio.channels.spi.SelectorProvider;35import java.util.ArrayDeque;36import java.util.Collections;37import java.util.Deque;38import java.util.HashSet;39import java.util.Iterator;40import java.util.Objects;41import java.util.Set;42import java.util.concurrent.ConcurrentHashMap;43import java.util.function.Consumer;444546/**47* Base Selector implementation class.48*/4950public abstract class SelectorImpl51extends AbstractSelector52{53// The set of keys registered with this Selector54private final Set<SelectionKey> keys;5556// The set of keys with data ready for an operation57private final Set<SelectionKey> selectedKeys;5859// Public views of the key sets60private final Set<SelectionKey> publicKeys; // Immutable61private final Set<SelectionKey> publicSelectedKeys; // Removal allowed, but not addition6263// pending cancelled keys for deregistration64private final Deque<SelectionKeyImpl> cancelledKeys = new ArrayDeque<>();6566// used to check for reentrancy67private boolean inSelect;6869protected SelectorImpl(SelectorProvider sp) {70super(sp);71keys = ConcurrentHashMap.newKeySet();72selectedKeys = new HashSet<>();73publicKeys = Collections.unmodifiableSet(keys);74publicSelectedKeys = Util.ungrowableSet(selectedKeys);75}7677private void ensureOpen() {78if (!isOpen())79throw new ClosedSelectorException();80}8182@Override83public final Set<SelectionKey> keys() {84ensureOpen();85return publicKeys;86}8788@Override89public final Set<SelectionKey> selectedKeys() {90ensureOpen();91return publicSelectedKeys;92}9394/**95* Marks the beginning of a select operation that might block96*/97protected final void begin(boolean blocking) {98if (blocking) begin();99}100101/**102* Marks the end of a select operation that may have blocked103*/104protected final void end(boolean blocking) {105if (blocking) end();106}107108/**109* Selects the keys for channels that are ready for I/O operations.110*111* @param action the action to perform, can be null112* @param timeout timeout in milliseconds to wait, 0 to not wait, -1 to113* wait indefinitely114*/115protected abstract int doSelect(Consumer<SelectionKey> action, long timeout)116throws IOException;117118private int lockAndDoSelect(Consumer<SelectionKey> action, long timeout)119throws IOException120{121synchronized (this) {122ensureOpen();123if (inSelect)124throw new IllegalStateException("select in progress");125inSelect = true;126try {127synchronized (publicSelectedKeys) {128return doSelect(action, timeout);129}130} finally {131inSelect = false;132}133}134}135136@Override137public final int select(long timeout) throws IOException {138if (timeout < 0)139throw new IllegalArgumentException("Negative timeout");140return lockAndDoSelect(null, (timeout == 0) ? -1 : timeout);141}142143@Override144public final int select() throws IOException {145return lockAndDoSelect(null, -1);146}147148@Override149public final int selectNow() throws IOException {150return lockAndDoSelect(null, 0);151}152153@Override154public final int select(Consumer<SelectionKey> action, long timeout)155throws IOException156{157Objects.requireNonNull(action);158if (timeout < 0)159throw new IllegalArgumentException("Negative timeout");160return lockAndDoSelect(action, (timeout == 0) ? -1 : timeout);161}162163@Override164public final int select(Consumer<SelectionKey> action) throws IOException {165Objects.requireNonNull(action);166return lockAndDoSelect(action, -1);167}168169@Override170public final int selectNow(Consumer<SelectionKey> action) throws IOException {171Objects.requireNonNull(action);172return lockAndDoSelect(action, 0);173}174175/**176* Invoked by implCloseSelector to close the selector.177*/178protected abstract void implClose() throws IOException;179180@Override181public final void implCloseSelector() throws IOException {182wakeup();183synchronized (this) {184implClose();185synchronized (publicSelectedKeys) {186// Deregister channels187Iterator<SelectionKey> i = keys.iterator();188while (i.hasNext()) {189SelectionKeyImpl ski = (SelectionKeyImpl)i.next();190deregister(ski);191SelectableChannel selch = ski.channel();192if (!selch.isOpen() && !selch.isRegistered())193((SelChImpl)selch).kill();194selectedKeys.remove(ski);195i.remove();196}197assert selectedKeys.isEmpty() && keys.isEmpty();198}199}200}201202@Override203protected final SelectionKey register(AbstractSelectableChannel ch,204int ops,205Object attachment)206{207if (!(ch instanceof SelChImpl))208throw new IllegalSelectorException();209SelectionKeyImpl k = new SelectionKeyImpl((SelChImpl)ch, this);210if (attachment != null)211k.attach(attachment);212213// register (if needed) before adding to key set214implRegister(k);215216// add to the selector's key set, removing it immediately if the selector217// is closed. The key is not in the channel's key set at this point but218// it may be observed by a thread iterating over the selector's key set.219keys.add(k);220try {221k.interestOps(ops);222} catch (ClosedSelectorException e) {223assert ch.keyFor(this) == null;224keys.remove(k);225k.cancel();226throw e;227}228return k;229}230231/**232* Register the key in the selector.233*234* The default implementation checks if the selector is open. It should235* be overridden by selector implementations as needed.236*/237protected void implRegister(SelectionKeyImpl ski) {238ensureOpen();239}240241/**242* Removes the key from the selector243*/244protected abstract void implDereg(SelectionKeyImpl ski) throws IOException;245246/**247* Queue a cancelled key for the next selection operation248*/249public void cancel(SelectionKeyImpl ski) {250synchronized (cancelledKeys) {251cancelledKeys.addLast(ski);252}253}254255/**256* Invoked by selection operations to process the cancelled keys257*/258protected final void processDeregisterQueue() throws IOException {259assert Thread.holdsLock(this);260assert Thread.holdsLock(publicSelectedKeys);261262synchronized (cancelledKeys) {263SelectionKeyImpl ski;264while ((ski = cancelledKeys.pollFirst()) != null) {265// remove the key from the selector266implDereg(ski);267268selectedKeys.remove(ski);269keys.remove(ski);270271// remove from channel's key set272deregister(ski);273274SelectableChannel ch = ski.channel();275if (!ch.isOpen() && !ch.isRegistered())276((SelChImpl)ch).kill();277}278}279}280281/**282* Invoked by selection operations to handle ready events. If an action283* is specified then it is invoked to handle the key, otherwise the key284* is added to the selected-key set (or updated when it is already in the285* set).286*/287protected final int processReadyEvents(int rOps,288SelectionKeyImpl ski,289Consumer<SelectionKey> action) {290if (action != null) {291ski.translateAndSetReadyOps(rOps);292if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {293action.accept(ski);294ensureOpen();295return 1;296}297} else {298assert Thread.holdsLock(publicSelectedKeys);299if (selectedKeys.contains(ski)) {300if (ski.translateAndUpdateReadyOps(rOps)) {301return 1;302}303} else {304ski.translateAndSetReadyOps(rOps);305if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {306selectedKeys.add(ski);307return 1;308}309}310}311return 0;312}313314/**315* Invoked by interestOps to ensure the interest ops are updated at the316* next selection operation.317*/318protected abstract void setEventOps(SelectionKeyImpl ski);319}320321322