jdk/src/share/classes/java/nio/channels/spi/AbstractInterruptibleChannel.java
changeset 2 90ce3da70b43
child 5506 202f599c92aa
--- /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>&nbsp;...&nbsp;<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>&nbsp;...&nbsp;<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>&nbsp;...&nbsp;<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);
+    }
+}