Save This Page
Home » openjdk-7 » java » nio » channels » spi » [javadoc | source]
    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>&nbsp;...&nbsp;<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>&nbsp;...&nbsp;<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>&nbsp;...&nbsp;<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   }

Save This Page
Home » openjdk-7 » java » nio » channels » spi » [javadoc | source]