1 /* 2 * Copyright (c) 2000, 2010, 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.lang.reflect.Method; 33 import java.lang.reflect.InvocationTargetException; 34 import java.nio.channels.*; 35 import java.security.AccessController; 36 import java.security.PrivilegedAction; 37 import sun.nio.ch.Interruptible; 38 39 40 /** 41 * Base implementation class for interruptible channels. 42 * 43 * <p> This class encapsulates the low-level machinery required to implement 44 * the asynchronous closing and interruption of channels. A concrete channel 45 * class must invoke the {@link #begin begin} and {@link #end end} methods 46 * before and after, respectively, invoking an I/O operation that might block 47 * indefinitely. In order to ensure that the {@link #end end} method is always 48 * invoked, these methods should be used within a 49 * <tt>try</tt> ... <tt>finally</tt> block: <a name="be"> 50 * 51 * <blockquote><pre> 52 * boolean completed = false; 53 * try { 54 * begin(); 55 * completed = ...; // Perform blocking I/O operation 56 * return ...; // Return result 57 * } finally { 58 * end(completed); 59 * }</pre></blockquote> 60 * 61 * <p> The <tt>completed</tt> argument to the {@link #end end} method tells 62 * whether or not the I/O operation actually completed, that is, whether it had 63 * any effect that would be visible to the invoker. In the case of an 64 * operation that reads bytes, for example, this argument should be 65 * <tt>true</tt> if, and only if, some bytes were actually transferred into the 66 * invoker's target buffer. 67 * 68 * <p> A concrete channel class must also implement the {@link 69 * #implCloseChannel implCloseChannel} method in such a way that if it is 70 * invoked while another thread is blocked in a native I/O operation upon the 71 * channel then that operation will immediately return, either by throwing an 72 * exception or by returning normally. If a thread is interrupted or the 73 * channel upon which it is blocked is asynchronously closed then the channel's 74 * {@link #end end} method will throw the appropriate exception. 75 * 76 * <p> This class performs the synchronization required to implement the {@link 77 * java.nio.channels.Channel} specification. Implementations of the {@link 78 * #implCloseChannel implCloseChannel} method need not synchronize against 79 * other threads that might be attempting to close the channel. </p> 80 * 81 * 82 * @author Mark Reinhold 83 * @author JSR-51 Expert Group 84 * @since 1.4 85 */ 86 87 public abstract class AbstractInterruptibleChannel 88 implements Channel, InterruptibleChannel 89 { 90 91 private final Object closeLock = new Object(); 92 private volatile boolean open = true; 93 94 /** 95 * Initializes a new instance of this class. 96 */ 97 protected AbstractInterruptibleChannel() { } 98 99 /** 100 * Closes this channel. 101 * 102 * <p> If the channel has already been closed then this method returns 103 * immediately. Otherwise it marks the channel as closed and then invokes 104 * the {@link #implCloseChannel implCloseChannel} method in order to 105 * complete the close operation. </p> 106 * 107 * @throws IOException 108 * If an I/O error occurs 109 */ 110 public final void close() throws IOException { 111 synchronized (closeLock) { 112 if (!open) 113 return; 114 open = false; 115 implCloseChannel(); 116 } 117 } 118 119 /** 120 * Closes this channel. 121 * 122 * <p> This method is invoked by the {@link #close close} method in order 123 * to perform the actual work of closing the channel. This method is only 124 * invoked if the channel has not yet been closed, and it is never invoked 125 * more than once. 126 * 127 * <p> An implementation of this method must arrange for any other thread 128 * that is blocked in an I/O operation upon this channel to return 129 * immediately, either by throwing an exception or by returning normally. 130 * </p> 131 * 132 * @throws IOException 133 * If an I/O error occurs while closing the channel 134 */ 135 protected abstract void implCloseChannel() throws IOException; 136 137 public final boolean isOpen() { 138 return open; 139 } 140 141 142 // -- Interruption machinery -- 143 144 private Interruptible interruptor; 145 private volatile Thread interrupted; 146 147 /** 148 * Marks the beginning of an I/O operation that might block indefinitely. 149 * 150 * <p> This method should be invoked in tandem with the {@link #end end} 151 * method, using a <tt>try</tt> ... <tt>finally</tt> block as 152 * shown <a href="#be">above</a>, in order to implement asynchronous 153 * closing and interruption for this channel. </p> 154 */ 155 protected final void begin() { 156 if (interruptor == null) { 157 interruptor = new Interruptible() { 158 public void interrupt(Thread target) { 159 synchronized (closeLock) { 160 if (!open) 161 return; 162 open = false; 163 interrupted = target; 164 try { 165 AbstractInterruptibleChannel.this.implCloseChannel(); 166 } catch (IOException x) { } 167 } 168 }}; 169 } 170 blockedOn(interruptor); 171 Thread me = Thread.currentThread(); 172 if (me.isInterrupted()) 173 interruptor.interrupt(me); 174 } 175 176 /** 177 * Marks the end of an I/O operation that might block indefinitely. 178 * 179 * <p> This method should be invoked in tandem with the {@link #begin 180 * begin} method, using a <tt>try</tt> ... <tt>finally</tt> block 181 * as shown <a href="#be">above</a>, in order to implement asynchronous 182 * closing and interruption for this channel. </p> 183 * 184 * @param completed 185 * <tt>true</tt> if, and only if, the I/O operation completed 186 * successfully, that is, had some effect that would be visible to 187 * the operation's invoker 188 * 189 * @throws AsynchronousCloseException 190 * If the channel was asynchronously closed 191 * 192 * @throws ClosedByInterruptException 193 * If the thread blocked in the I/O operation was interrupted 194 */ 195 protected final void end(boolean completed) 196 throws AsynchronousCloseException 197 { 198 blockedOn(null); 199 Thread interrupted = this.interrupted; 200 if (interrupted != null && interrupted == Thread.currentThread()) { 201 interrupted = null; 202 throw new ClosedByInterruptException(); 203 } 204 if (!completed && !open) 205 throw new AsynchronousCloseException(); 206 } 207 208 209 // -- sun.misc.SharedSecrets -- 210 static void blockedOn(Interruptible intr) { // package-private 211 sun.misc.SharedSecrets.getJavaLangAccess().blockedOn(Thread.currentThread(), 212 intr); 213 } 214 }