--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/channels/spi/AbstractInterruptibleChannel.java Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2000-2005 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ */
+
+package java.nio.channels.spi;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+import java.nio.channels.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import sun.nio.ch.Interruptible;
+
+
+/**
+ * Base implementation class for interruptible channels.
+ *
+ * <p> This class encapsulates the low-level machinery required to implement
+ * the asynchronous closing and interruption of channels. A concrete channel
+ * class must invoke the {@link #begin begin} and {@link #end end} methods
+ * before and after, respectively, invoking an I/O operation that might block
+ * indefinitely. In order to ensure that the {@link #end end} method is always
+ * invoked, these methods should be used within a
+ * <tt>try</tt> ... <tt>finally</tt> block: <a name="be">
+ *
+ * <blockquote><pre>
+ * boolean completed = false;
+ * try {
+ * begin();
+ * completed = ...; // Perform blocking I/O operation
+ * return ...; // Return result
+ * } finally {
+ * end(completed);
+ * }</pre></blockquote>
+ *
+ * <p> The <tt>completed</tt> argument to the {@link #end end} method tells
+ * whether or not the I/O operation actually completed, that is, whether it had
+ * any effect that would be visible to the invoker. In the case of an
+ * operation that reads bytes, for example, this argument should be
+ * <tt>true</tt> if, and only if, some bytes were actually transferred into the
+ * invoker's target buffer.
+ *
+ * <p> A concrete channel class must also implement the {@link
+ * #implCloseChannel implCloseChannel} method in such a way that if it is
+ * invoked while another thread is blocked in a native I/O operation upon the
+ * channel then that operation will immediately return, either by throwing an
+ * exception or by returning normally. If a thread is interrupted or the
+ * channel upon which it is blocked is asynchronously closed then the channel's
+ * {@link #end end} method will throw the appropriate exception.
+ *
+ * <p> This class performs the synchronization required to implement the {@link
+ * java.nio.channels.Channel} specification. Implementations of the {@link
+ * #implCloseChannel implCloseChannel} method need not synchronize against
+ * other threads that might be attempting to close the channel. </p>
+ *
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public abstract class AbstractInterruptibleChannel
+ implements Channel, InterruptibleChannel
+{
+
+ private Object closeLock = new Object();
+ private volatile boolean open = true;
+
+ /**
+ * Initializes a new instance of this class.
+ */
+ protected AbstractInterruptibleChannel() { }
+
+ /**
+ * Closes this channel.
+ *
+ * <p> If the channel has already been closed then this method returns
+ * immediately. Otherwise it marks the channel as closed and then invokes
+ * the {@link #implCloseChannel implCloseChannel} method in order to
+ * complete the close operation. </p>
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ public final void close() throws IOException {
+ synchronized (closeLock) {
+ if (!open)
+ return;
+ open = false;
+ implCloseChannel();
+ }
+ }
+
+ /**
+ * Closes this channel.
+ *
+ * <p> This method is invoked by the {@link #close close} method in order
+ * to perform the actual work of closing the channel. This method is only
+ * invoked if the channel has not yet been closed, and it is never invoked
+ * more than once.
+ *
+ * <p> An implementation of this method must arrange for any other thread
+ * that is blocked in an I/O operation upon this channel to return
+ * immediately, either by throwing an exception or by returning normally.
+ * </p>
+ *
+ * @throws IOException
+ * If an I/O error occurs while closing the channel
+ */
+ protected abstract void implCloseChannel() throws IOException;
+
+ public final boolean isOpen() {
+ return open;
+ }
+
+
+ // -- Interruption machinery --
+
+ private Interruptible interruptor;
+ private volatile boolean interrupted = false;
+
+ /**
+ * Marks the beginning of an I/O operation that might block indefinitely.
+ *
+ * <p> This method should be invoked in tandem with the {@link #end end}
+ * method, using a <tt>try</tt> ... <tt>finally</tt> block as
+ * shown <a href="#be">above</a>, in order to implement asynchronous
+ * closing and interruption for this channel. </p>
+ */
+ protected final void begin() {
+ if (interruptor == null) {
+ interruptor = new Interruptible() {
+ public void interrupt() {
+ synchronized (closeLock) {
+ if (!open)
+ return;
+ interrupted = true;
+ open = false;
+ try {
+ AbstractInterruptibleChannel.this.implCloseChannel();
+ } catch (IOException x) { }
+ }
+ }};
+ }
+ blockedOn(interruptor);
+ if (Thread.currentThread().isInterrupted())
+ interruptor.interrupt();
+ }
+
+ /**
+ * Marks the end of an I/O operation that might block indefinitely.
+ *
+ * <p> This method should be invoked in tandem with the {@link #begin
+ * begin} method, using a <tt>try</tt> ... <tt>finally</tt> block
+ * as shown <a href="#be">above</a>, in order to implement asynchronous
+ * closing and interruption for this channel. </p>
+ *
+ * @param completed
+ * <tt>true</tt> if, and only if, the I/O operation completed
+ * successfully, that is, had some effect that would be visible to
+ * the operation's invoker
+ *
+ * @throws AsynchronousCloseException
+ * If the channel was asynchronously closed
+ *
+ * @throws ClosedByInterruptException
+ * If the thread blocked in the I/O operation was interrupted
+ */
+ protected final void end(boolean completed)
+ throws AsynchronousCloseException
+ {
+ blockedOn(null);
+ if (completed) {
+ interrupted = false;
+ return;
+ }
+ if (interrupted) throw new ClosedByInterruptException();
+ if (!open) throw new AsynchronousCloseException();
+ }
+
+
+ // -- sun.misc.SharedSecrets --
+ static void blockedOn(Interruptible intr) { // package-private
+ sun.misc.SharedSecrets.getJavaLangAccess().blockedOn(Thread.currentThread(),
+ intr);
+ }
+}