content: /*
   * Copyright (C) 2014 The Android Open Source Project
   * Copyright (c) 2000, 2013, Oracle and/or its affiliates. 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.  Oracle designates this
   * particular file as subject to the "Classpath" exception as provided
   * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   * or visit www.oracle.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:
   *
   * <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
   * 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 final 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 Thread interrupted;
  
      /**
       * 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(Thread target) {
                          synchronized (closeLock) {
                              if (!open)
                                  return;
                              open = false;
                              interrupted = target;
                              try {
                                  AbstractInterruptibleChannel.this.implCloseChannel();
                              } catch (IOException x) { }
                          }
                      }};
          }
          blockedOn(interruptor);
          Thread me = Thread.currentThread();
          if (me.isInterrupted())
              interruptor.interrupt(me);
      }
  
      /**
       * 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);
          Thread interrupted = this.interrupted;
          if (interrupted != null && interrupted == Thread.currentThread()) {
              interrupted = null;
              throw new ClosedByInterruptException();
          }
          if (!completed && !open)
              throw new AsynchronousCloseException();
      }
  
  
      // -- sun.misc.SharedSecrets --
      static void blockedOn(Interruptible intr) {         // package-private
          // Android-changed: Call Thread.currentThread().blockedOn() directly.
          Thread.currentThread().blockedOn(intr);
      }
  }
  