1 /* 2 * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /* 27 */ 28 29 package java.nio.channels.spi; 30 31 import java.io.IOException; 32 import java.nio.channels.*; 33 import jdk.internal.misc.SharedSecrets; 34 import sun.nio.ch.Interruptible; 35 36 37 /** 38 * Base implementation class for interruptible channels. 39 * 40 * <p> This class encapsulates the low-level machinery required to implement 41 * the asynchronous closing and interruption of channels. A concrete channel 42 * class must invoke the {@link #begin begin} and {@link #end end} methods 43 * before and after, respectively, invoking an I/O operation that might block 44 * indefinitely. In order to ensure that the {@link #end end} method is always 45 * invoked, these methods should be used within a 46 * {@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 operation 53 * return ...; // Return result 54 * } finally { 55 * end(completed); 56 * }</pre></blockquote> 57 * 58 * <p> The {@code completed} argument to the {@link #end end} method tells 59 * whether or not the I/O operation actually completed, that is, whether it had 60 * any effect that would be visible to the invoker. In the case of an 61 * operation that reads bytes, for example, this argument should be 62 * {@code true} if, and only if, some bytes were actually transferred into the 63 * invoker's target buffer. 64 * 65 * <p> A concrete channel class must also implement the {@link 66 * #implCloseChannel implCloseChannel} method in such a way that if it is 67 * invoked while another thread is blocked in a native I/O operation upon the 68 * channel then that operation will immediately return, either by throwing an 69 * exception or by returning normally. If a thread is interrupted or the 70 * channel upon which it is blocked is asynchronously closed then the channel's 71 * {@link #end end} method will throw the appropriate exception. 72 * 73 * <p> This class performs the synchronization required to implement the {@link 74 * java.nio.channels.Channel} specification. Implementations of the {@link 75 * #implCloseChannel implCloseChannel} method need not synchronize against 76 * other threads that might be attempting to close the channel. </p> 77 * 78 * 79 * @author Mark Reinhold 80 * @author JSR-51 Expert Group 81 * @since 1.4 82 */ 83 84 public abstract class AbstractInterruptibleChannel 85 implements Channel, InterruptibleChannel 86 { 87 88 private final Object closeLock = new Object(); 89 private volatile boolean closed; 90 91 /** 92 * Initializes a new instance of this class. 93 */ 94 protected AbstractInterruptibleChannel() { } 95 96 /** 97 * Closes this channel. 98 * 99 * <p> If the channel has already been closed then this method returns 100 * immediately. Otherwise it marks the channel as closed and then invokes 101 * the {@link #implCloseChannel implCloseChannel} method in order to 102 * complete the close operation. </p> 103 * 104 * @throws IOException 105 * If an I/O error occurs 106 */ 107 public final void close() throws IOException { 108 synchronized (closeLock) { 109 if (closed) 110 return; 111 closed = true; 112 implCloseChannel(); 113 } 114 } 115 116 /** 117 * Closes this channel. 118 * 119 * <p> This method is invoked by the {@link #close close} method in order 120 * to perform the actual work of closing the channel. This method is only 121 * invoked if the channel has not yet been closed, and it is never invoked 122 * more than once. 123 * 124 * <p> An implementation of this method must arrange for any other thread 125 * that is blocked in an I/O operation upon this channel to return 126 * immediately, either by throwing an exception or by returning normally. 127 * </p> 128 * 129 * @throws IOException 130 * If an I/O error occurs while closing the channel 131 */ 132 protected abstract void implCloseChannel() throws IOException; 133 134 public final boolean isOpen() { 135 return !closed; 136 } 137 138 139 // -- Interruption machinery -- 140 141 private Interruptible interruptor; 142 private volatile Thread interrupted; 143 144 /** 145 * Marks the beginning of an I/O operation that might block indefinitely. 146 * 147 * <p> This method should be invoked in tandem with the {@link #end end} 148 * method, using a {@code try} ... {@code finally} block as 149 * shown <a href="#be">above</a>, in order to implement asynchronous 150 * closing and interruption for this channel. </p> 151 */ 152 protected final void begin() { 153 if (interruptor == null) { 154 interruptor = new Interruptible() { 155 public void interrupt(Thread target) { 156 synchronized (closeLock) { 157 if (closed) 158 return; 159 closed = true; 160 interrupted = target; 161 try { 162 AbstractInterruptibleChannel.this.implCloseChannel(); 163 } catch (IOException x) { } 164 } 165 }}; 166 } 167 blockedOn(interruptor); 168 Thread me = Thread.currentThread(); 169 if (me.isInterrupted()) 170 interruptor.interrupt(me); 171 } 172 173 /** 174 * Marks the end of an I/O operation that might block indefinitely. 175 * 176 * <p> This method should be invoked in tandem with the {@link #begin 177 * begin} method, using a {@code try} ... {@code finally} block 178 * as shown <a href="#be">above</a>, in order to implement asynchronous 179 * closing and interruption for this channel. </p> 180 * 181 * @param completed 182 * {@code true} if, and only if, the I/O operation completed 183 * successfully, that is, had some effect that would be visible to 184 * the operation's invoker 185 * 186 * @throws AsynchronousCloseException 187 * If the channel was asynchronously closed 188 * 189 * @throws ClosedByInterruptException 190 * If the thread blocked in the I/O operation was interrupted 191 */ 192 protected final void end(boolean completed) 193 throws AsynchronousCloseException 194 { 195 blockedOn(null); 196 Thread interrupted = this.interrupted; 197 if (interrupted != null && interrupted == Thread.currentThread()) { 198 this.interrupted = null; 199 throw new ClosedByInterruptException(); 200 } 201 if (!completed && closed) 202 throw new AsynchronousCloseException(); 203 } 204 205 206 // -- jdk.internal.misc.SharedSecrets -- 207 static void blockedOn(Interruptible intr) { // package-private 208 SharedSecrets.getJavaLangAccess().blockedOn(intr); 209 } 210 }