Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/java/nio/channels/spi/AbstractInterruptibleChannel.java
38918 views
/*1* Copyright (c) 2000, 2013, 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*/2425/*26*/2728package java.nio.channels.spi;2930import java.io.IOException;31import java.lang.reflect.Method;32import java.lang.reflect.InvocationTargetException;33import java.nio.channels.*;34import java.security.AccessController;35import java.security.PrivilegedAction;36import sun.nio.ch.Interruptible;373839/**40* Base implementation class for interruptible channels.41*42* <p> This class encapsulates the low-level machinery required to implement43* the asynchronous closing and interruption of channels. A concrete channel44* class must invoke the {@link #begin begin} and {@link #end end} methods45* before and after, respectively, invoking an I/O operation that might block46* indefinitely. In order to ensure that the {@link #end end} method is always47* invoked, these methods should be used within a48* <tt>try</tt> ... <tt>finally</tt> block:49*50* <blockquote><pre>51* boolean completed = false;52* try {53* begin();54* completed = ...; // Perform blocking I/O operation55* return ...; // Return result56* } finally {57* end(completed);58* }</pre></blockquote>59*60* <p> The <tt>completed</tt> argument to the {@link #end end} method tells61* whether or not the I/O operation actually completed, that is, whether it had62* any effect that would be visible to the invoker. In the case of an63* operation that reads bytes, for example, this argument should be64* <tt>true</tt> if, and only if, some bytes were actually transferred into the65* invoker's target buffer.66*67* <p> A concrete channel class must also implement the {@link68* #implCloseChannel implCloseChannel} method in such a way that if it is69* invoked while another thread is blocked in a native I/O operation upon the70* channel then that operation will immediately return, either by throwing an71* exception or by returning normally. If a thread is interrupted or the72* channel upon which it is blocked is asynchronously closed then the channel's73* {@link #end end} method will throw the appropriate exception.74*75* <p> This class performs the synchronization required to implement the {@link76* java.nio.channels.Channel} specification. Implementations of the {@link77* #implCloseChannel implCloseChannel} method need not synchronize against78* other threads that might be attempting to close the channel. </p>79*80*81* @author Mark Reinhold82* @author JSR-51 Expert Group83* @since 1.484*/8586public abstract class AbstractInterruptibleChannel87implements Channel, InterruptibleChannel88{8990private final Object closeLock = new Object();91private volatile boolean open = true;9293/**94* Initializes a new instance of this class.95*/96protected AbstractInterruptibleChannel() { }9798/**99* Closes this channel.100*101* <p> If the channel has already been closed then this method returns102* immediately. Otherwise it marks the channel as closed and then invokes103* the {@link #implCloseChannel implCloseChannel} method in order to104* complete the close operation. </p>105*106* @throws IOException107* If an I/O error occurs108*/109public final void close() throws IOException {110synchronized (closeLock) {111if (!open)112return;113open = false;114implCloseChannel();115}116}117118/**119* Closes this channel.120*121* <p> This method is invoked by the {@link #close close} method in order122* to perform the actual work of closing the channel. This method is only123* invoked if the channel has not yet been closed, and it is never invoked124* more than once.125*126* <p> An implementation of this method must arrange for any other thread127* that is blocked in an I/O operation upon this channel to return128* immediately, either by throwing an exception or by returning normally.129* </p>130*131* @throws IOException132* If an I/O error occurs while closing the channel133*/134protected abstract void implCloseChannel() throws IOException;135136public final boolean isOpen() {137return open;138}139140141// -- Interruption machinery --142143private Interruptible interruptor;144private volatile Thread interrupted;145146/**147* Marks the beginning of an I/O operation that might block indefinitely.148*149* <p> This method should be invoked in tandem with the {@link #end end}150* method, using a <tt>try</tt> ... <tt>finally</tt> block as151* shown <a href="#be">above</a>, in order to implement asynchronous152* closing and interruption for this channel. </p>153*/154protected final void begin() {155if (interruptor == null) {156interruptor = new Interruptible() {157public void interrupt(Thread target) {158synchronized (closeLock) {159if (!open)160return;161open = false;162interrupted = target;163try {164AbstractInterruptibleChannel.this.implCloseChannel();165} catch (IOException x) { }166}167}};168}169blockedOn(interruptor);170Thread me = Thread.currentThread();171if (me.isInterrupted())172interruptor.interrupt(me);173}174175/**176* Marks the end of an I/O operation that might block indefinitely.177*178* <p> This method should be invoked in tandem with the {@link #begin179* begin} method, using a <tt>try</tt> ... <tt>finally</tt> block180* as shown <a href="#be">above</a>, in order to implement asynchronous181* closing and interruption for this channel. </p>182*183* @param completed184* <tt>true</tt> if, and only if, the I/O operation completed185* successfully, that is, had some effect that would be visible to186* the operation's invoker187*188* @throws AsynchronousCloseException189* If the channel was asynchronously closed190*191* @throws ClosedByInterruptException192* If the thread blocked in the I/O operation was interrupted193*/194protected final void end(boolean completed)195throws AsynchronousCloseException196{197blockedOn(null);198Thread interrupted = this.interrupted;199if (interrupted != null && interrupted == Thread.currentThread()) {200interrupted = null;201throw new ClosedByInterruptException();202}203if (!completed && !open)204throw new AsynchronousCloseException();205}206207208// -- sun.misc.SharedSecrets --209static void blockedOn(Interruptible intr) { // package-private210sun.misc.SharedSecrets.getJavaLangAccess().blockedOn(Thread.currentThread(),211intr);212}213}214215216