Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/java/nio/channels/spi/AbstractSelectableChannel.java
38918 views
/*1* Copyright (c) 2000, 2018, 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 java.nio.channels.spi;2627import java.io.IOException;28import java.nio.channels.CancelledKeyException;29import java.nio.channels.ClosedChannelException;30import java.nio.channels.ClosedSelectorException;31import java.nio.channels.IllegalBlockingModeException;32import java.nio.channels.IllegalSelectorException;33import java.nio.channels.SelectableChannel;34import java.nio.channels.SelectionKey;35import java.nio.channels.Selector;363738/**39* Base implementation class for selectable channels.40*41* <p> This class defines methods that handle the mechanics of channel42* registration, deregistration, and closing. It maintains the current43* blocking mode of this channel as well as its current set of selection keys.44* It performs all of the synchronization required to implement the {@link45* java.nio.channels.SelectableChannel} specification. Implementations of the46* abstract protected methods defined in this class need not synchronize47* against other threads that might be engaged in the same operations. </p>48*49*50* @author Mark Reinhold51* @author Mike McCloskey52* @author JSR-51 Expert Group53* @since 1.454*/5556public abstract class AbstractSelectableChannel57extends SelectableChannel58{5960// The provider that created this channel61private final SelectorProvider provider;6263// Keys that have been created by registering this channel with selectors.64// They are saved because if this channel is closed the keys must be65// deregistered. Protected by keyLock.66//67private SelectionKey[] keys = null;68private int keyCount = 0;6970// Lock for key set and count71private final Object keyLock = new Object();7273// Lock for registration and configureBlocking operations74private final Object regLock = new Object();7576// True when non-blocking, need regLock to change;77private volatile boolean nonBlocking;7879/**80* Initializes a new instance of this class.81*82* @param provider83* The provider that created this channel84*/85protected AbstractSelectableChannel(SelectorProvider provider) {86this.provider = provider;87}8889/**90* Returns the provider that created this channel.91*92* @return The provider that created this channel93*/94public final SelectorProvider provider() {95return provider;96}979899// -- Utility methods for the key set --100101private void addKey(SelectionKey k) {102assert Thread.holdsLock(keyLock);103int i = 0;104if ((keys != null) && (keyCount < keys.length)) {105// Find empty element of key array106for (i = 0; i < keys.length; i++)107if (keys[i] == null)108break;109} else if (keys == null) {110keys = new SelectionKey[3];111} else {112// Grow key array113int n = keys.length * 2;114SelectionKey[] ks = new SelectionKey[n];115for (i = 0; i < keys.length; i++)116ks[i] = keys[i];117keys = ks;118i = keyCount;119}120keys[i] = k;121keyCount++;122}123124private SelectionKey findKey(Selector sel) {125synchronized (keyLock) {126if (keys == null)127return null;128for (int i = 0; i < keys.length; i++)129if ((keys[i] != null) && (keys[i].selector() == sel))130return keys[i];131return null;132}133}134135void removeKey(SelectionKey k) { // package-private136synchronized (keyLock) {137for (int i = 0; i < keys.length; i++)138if (keys[i] == k) {139keys[i] = null;140keyCount--;141}142((AbstractSelectionKey)k).invalidate();143}144}145146private boolean haveValidKeys() {147synchronized (keyLock) {148if (keyCount == 0)149return false;150for (int i = 0; i < keys.length; i++) {151if ((keys[i] != null) && keys[i].isValid())152return true;153}154return false;155}156}157158159// -- Registration --160161public final boolean isRegistered() {162synchronized (keyLock) {163return keyCount != 0;164}165}166167public final SelectionKey keyFor(Selector sel) {168return findKey(sel);169}170171/**172* Registers this channel with the given selector, returning a selection key.173*174* <p> This method first verifies that this channel is open and that the175* given initial interest set is valid.176*177* <p> If this channel is already registered with the given selector then178* the selection key representing that registration is returned after179* setting its interest set to the given value.180*181* <p> Otherwise this channel has not yet been registered with the given182* selector, so the {@link AbstractSelector#register register} method of183* the selector is invoked while holding the appropriate locks. The184* resulting key is added to this channel's key set before being returned.185* </p>186*187* @throws ClosedSelectorException {@inheritDoc}188*189* @throws IllegalBlockingModeException {@inheritDoc}190*191* @throws IllegalSelectorException {@inheritDoc}192*193* @throws CancelledKeyException {@inheritDoc}194*195* @throws IllegalArgumentException {@inheritDoc}196*/197public final SelectionKey register(Selector sel, int ops,198Object att)199throws ClosedChannelException200{201synchronized (regLock) {202if (!isOpen())203throw new ClosedChannelException();204if ((ops & ~validOps()) != 0)205throw new IllegalArgumentException();206if (isBlocking())207throw new IllegalBlockingModeException();208SelectionKey k = findKey(sel);209if (k != null) {210k.interestOps(ops);211k.attach(att);212}213if (k == null) {214// New registration215synchronized (keyLock) {216if (!isOpen())217throw new ClosedChannelException();218k = ((AbstractSelector)sel).register(this, ops, att);219addKey(k);220}221}222return k;223}224}225226227// -- Closing --228229/**230* Closes this channel.231*232* <p> This method, which is specified in the {@link233* AbstractInterruptibleChannel} class and is invoked by the {@link234* java.nio.channels.Channel#close close} method, in turn invokes the235* {@link #implCloseSelectableChannel implCloseSelectableChannel} method in236* order to perform the actual work of closing this channel. It then237* cancels all of this channel's keys. </p>238*/239protected final void implCloseChannel() throws IOException {240implCloseSelectableChannel();241synchronized (keyLock) {242int count = (keys == null) ? 0 : keys.length;243for (int i = 0; i < count; i++) {244SelectionKey k = keys[i];245if (k != null)246k.cancel();247}248}249}250251/**252* Closes this selectable channel.253*254* <p> This method is invoked by the {@link java.nio.channels.Channel#close255* close} method in order to perform the actual work of closing the256* channel. This method is only invoked if the channel has not yet been257* closed, and it is never invoked more than once.258*259* <p> An implementation of this method must arrange for any other thread260* that is blocked in an I/O operation upon this channel to return261* immediately, either by throwing an exception or by returning normally.262* </p>263*264* @throws IOException265* If an I/O error occurs266*/267protected abstract void implCloseSelectableChannel() throws IOException;268269270// -- Blocking --271272public final boolean isBlocking() {273return !nonBlocking;274}275276public final Object blockingLock() {277return regLock;278}279280/**281* Adjusts this channel's blocking mode.282*283* <p> If the given blocking mode is different from the current blocking284* mode then this method invokes the {@link #implConfigureBlocking285* implConfigureBlocking} method, while holding the appropriate locks, in286* order to change the mode. </p>287*/288public final SelectableChannel configureBlocking(boolean block)289throws IOException290{291synchronized (regLock) {292if (!isOpen())293throw new ClosedChannelException();294boolean blocking = !nonBlocking;295if (block != blocking) {296if (block && haveValidKeys())297throw new IllegalBlockingModeException();298implConfigureBlocking(block);299nonBlocking = !block;300}301}302return this;303}304305/**306* Adjusts this channel's blocking mode.307*308* <p> This method is invoked by the {@link #configureBlocking309* configureBlocking} method in order to perform the actual work of310* changing the blocking mode. This method is only invoked if the new mode311* is different from the current mode. </p>312*313* @param block If <tt>true</tt> then this channel will be placed in314* blocking mode; if <tt>false</tt> then it will be placed315* non-blocking mode316*317* @throws IOException318* If an I/O error occurs319*/320protected abstract void implConfigureBlocking(boolean block)321throws IOException;322323}324325326