Path: blob/master/src/java.base/share/classes/java/nio/channels/spi/AbstractInterruptibleChannel.java
41161 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 java.nio.channels.spi;2627import java.io.IOException;28import java.nio.channels.AsynchronousCloseException;29import java.nio.channels.Channel;30import java.nio.channels.ClosedByInterruptException;31import java.nio.channels.InterruptibleChannel;3233import jdk.internal.access.SharedSecrets;34import sun.nio.ch.Interruptible;353637/**38* Base implementation class for interruptible channels.39*40* <p> This class encapsulates the low-level machinery required to implement41* the asynchronous closing and interruption of channels. A concrete channel42* class must invoke the {@link #begin begin} and {@link #end end} methods43* before and after, respectively, invoking an I/O operation that might block44* indefinitely. In order to ensure that the {@link #end end} method is always45* invoked, these methods should be used within a46* {@code try} ... {@code finally} block:47*48* <blockquote><pre id="be">49* boolean completed = false;50* try {51* begin();52* completed = ...; // Perform blocking I/O operation53* return ...; // Return result54* } finally {55* end(completed);56* }</pre></blockquote>57*58* <p> The {@code completed} argument to the {@link #end end} method tells59* whether or not the I/O operation actually completed, that is, whether it had60* any effect that would be visible to the invoker. In the case of an61* operation that reads bytes, for example, this argument should be62* {@code true} if, and only if, some bytes were actually transferred into the63* invoker's target buffer.64*65* <p> A concrete channel class must also implement the {@link66* #implCloseChannel implCloseChannel} method in such a way that if it is67* invoked while another thread is blocked in a native I/O operation upon the68* channel then that operation will immediately return, either by throwing an69* exception or by returning normally. If a thread is interrupted or the70* channel upon which it is blocked is asynchronously closed then the channel's71* {@link #end end} method will throw the appropriate exception.72*73* <p> This class performs the synchronization required to implement the {@link74* java.nio.channels.Channel} specification. Implementations of the {@link75* #implCloseChannel implCloseChannel} method need not synchronize against76* other threads that might be attempting to close the channel. </p>77*78*79* @author Mark Reinhold80* @author JSR-51 Expert Group81* @since 1.482*/8384public abstract class AbstractInterruptibleChannel85implements Channel, InterruptibleChannel86{87private final Object closeLock = new Object();88private volatile boolean closed;8990/**91* Initializes a new instance of this class.92*/93protected AbstractInterruptibleChannel() { }9495/**96* Closes this channel.97*98* <p> If the channel has already been closed then this method returns99* immediately. Otherwise it marks the channel as closed and then invokes100* the {@link #implCloseChannel implCloseChannel} method in order to101* complete the close operation. </p>102*103* @throws IOException104* If an I/O error occurs105*/106public final void close() throws IOException {107synchronized (closeLock) {108if (closed)109return;110closed = true;111implCloseChannel();112}113}114115/**116* Closes this channel.117*118* <p> This method is invoked by the {@link #close close} method in order119* to perform the actual work of closing the channel. This method is only120* invoked if the channel has not yet been closed, and it is never invoked121* more than once.122*123* <p> An implementation of this method must arrange for any other thread124* that is blocked in an I/O operation upon this channel to return125* immediately, either by throwing an exception or by returning normally.126* </p>127*128* @throws IOException129* If an I/O error occurs while closing the channel130*/131protected abstract void implCloseChannel() throws IOException;132133public final boolean isOpen() {134return !closed;135}136137138// -- Interruption machinery --139140private Interruptible interruptor;141private volatile Thread interrupted;142143/**144* Marks the beginning of an I/O operation that might block indefinitely.145*146* <p> This method should be invoked in tandem with the {@link #end end}147* method, using a {@code try} ... {@code finally} block as148* shown <a href="#be">above</a>, in order to implement asynchronous149* closing and interruption for this channel. </p>150*/151protected final void begin() {152if (interruptor == null) {153interruptor = new Interruptible() {154public void interrupt(Thread target) {155synchronized (closeLock) {156if (closed)157return;158closed = true;159interrupted = target;160try {161AbstractInterruptibleChannel.this.implCloseChannel();162} catch (IOException x) { }163}164}};165}166blockedOn(interruptor);167Thread me = Thread.currentThread();168if (me.isInterrupted())169interruptor.interrupt(me);170}171172/**173* Marks the end of an I/O operation that might block indefinitely.174*175* <p> This method should be invoked in tandem with the {@link #begin176* begin} method, using a {@code try} ... {@code finally} block177* as shown <a href="#be">above</a>, in order to implement asynchronous178* closing and interruption for this channel. </p>179*180* @param completed181* {@code true} if, and only if, the I/O operation completed182* successfully, that is, had some effect that would be visible to183* the operation's invoker184*185* @throws AsynchronousCloseException186* If the channel was asynchronously closed187*188* @throws ClosedByInterruptException189* If the thread blocked in the I/O operation was interrupted190*/191protected final void end(boolean completed)192throws AsynchronousCloseException193{194blockedOn(null);195Thread interrupted = this.interrupted;196if (interrupted != null && interrupted == Thread.currentThread()) {197this.interrupted = null;198throw new ClosedByInterruptException();199}200if (!completed && closed)201throw new AsynchronousCloseException();202}203204205// -- jdk.internal.access.SharedSecrets --206static void blockedOn(Interruptible intr) { // package-private207SharedSecrets.getJavaLangAccess().blockedOn(intr);208}209}210211212