Home | History | Annotate | Download | only in spi
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
      4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      5  *
      6  * This code is free software; you can redistribute it and/or modify it
      7  * under the terms of the GNU General Public License version 2 only, as
      8  * published by the Free Software Foundation.  Oracle designates this
      9  * particular file as subject to the "Classpath" exception as provided
     10  * by Oracle in the LICENSE file that accompanied this code.
     11  *
     12  * This code is distributed in the hope that it will be useful, but WITHOUT
     13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     15  * version 2 for more details (a copy is included in the LICENSE file that
     16  * accompanied this code).
     17  *
     18  * You should have received a copy of the GNU General Public License version
     19  * 2 along with this work; if not, write to the Free Software Foundation,
     20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     21  *
     22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     23  * or visit www.oracle.com if you need additional information or have any
     24  * questions.
     25  */
     26 
     27 /*
     28  */
     29 
     30 package java.nio.channels.spi;
     31 
     32 import java.io.IOException;
     33 import java.lang.reflect.Method;
     34 import java.lang.reflect.InvocationTargetException;
     35 import java.nio.channels.*;
     36 import java.security.AccessController;
     37 import java.security.PrivilegedAction;
     38 import sun.nio.ch.Interruptible;
     39 
     40 
     41 /**
     42  * Base implementation class for interruptible channels.
     43  *
     44  * <p> This class encapsulates the low-level machinery required to implement
     45  * the asynchronous closing and interruption of channels.  A concrete channel
     46  * class must invoke the {@link #begin begin} and {@link #end end} methods
     47  * before and after, respectively, invoking an I/O operation that might block
     48  * indefinitely.  In order to ensure that the {@link #end end} method is always
     49  * invoked, these methods should be used within a
     50  * <tt>try</tt>&nbsp;...&nbsp;<tt>finally</tt> block:
     51  *
     52  * <blockquote><pre>
     53  * boolean completed = false;
     54  * try {
     55  *     begin();
     56  *     completed = ...;    // Perform blocking I/O operation
     57  *     return ...;         // Return result
     58  * } finally {
     59  *     end(completed);
     60  * }</pre></blockquote>
     61  *
     62  * <p> The <tt>completed</tt> argument to the {@link #end end} method tells
     63  * whether or not the I/O operation actually completed, that is, whether it had
     64  * any effect that would be visible to the invoker.  In the case of an
     65  * operation that reads bytes, for example, this argument should be
     66  * <tt>true</tt> if, and only if, some bytes were actually transferred into the
     67  * invoker's target buffer.
     68  *
     69  * <p> A concrete channel class must also implement the {@link
     70  * #implCloseChannel implCloseChannel} method in such a way that if it is
     71  * invoked while another thread is blocked in a native I/O operation upon the
     72  * channel then that operation will immediately return, either by throwing an
     73  * exception or by returning normally.  If a thread is interrupted or the
     74  * channel upon which it is blocked is asynchronously closed then the channel's
     75  * {@link #end end} method will throw the appropriate exception.
     76  *
     77  * <p> This class performs the synchronization required to implement the {@link
     78  * java.nio.channels.Channel} specification.  Implementations of the {@link
     79  * #implCloseChannel implCloseChannel} method need not synchronize against
     80  * other threads that might be attempting to close the channel.  </p>
     81  *
     82  *
     83  * @author Mark Reinhold
     84  * @author JSR-51 Expert Group
     85  * @since 1.4
     86  */
     87 
     88 public abstract class AbstractInterruptibleChannel
     89     implements Channel, InterruptibleChannel
     90 {
     91 
     92     private final Object closeLock = new Object();
     93     private volatile boolean open = true;
     94 
     95     /**
     96      * Initializes a new instance of this class.
     97      */
     98     protected AbstractInterruptibleChannel() { }
     99 
    100     /**
    101      * Closes this channel.
    102      *
    103      * <p> If the channel has already been closed then this method returns
    104      * immediately.  Otherwise it marks the channel as closed and then invokes
    105      * the {@link #implCloseChannel implCloseChannel} method in order to
    106      * complete the close operation.  </p>
    107      *
    108      * @throws  IOException
    109      *          If an I/O error occurs
    110      */
    111     public final void close() throws IOException {
    112         synchronized (closeLock) {
    113             if (!open)
    114                 return;
    115             open = false;
    116             implCloseChannel();
    117         }
    118     }
    119 
    120     /**
    121      * Closes this channel.
    122      *
    123      * <p> This method is invoked by the {@link #close close} method in order
    124      * to perform the actual work of closing the channel.  This method is only
    125      * invoked if the channel has not yet been closed, and it is never invoked
    126      * more than once.
    127      *
    128      * <p> An implementation of this method must arrange for any other thread
    129      * that is blocked in an I/O operation upon this channel to return
    130      * immediately, either by throwing an exception or by returning normally.
    131      * </p>
    132      *
    133      * @throws  IOException
    134      *          If an I/O error occurs while closing the channel
    135      */
    136     protected abstract void implCloseChannel() throws IOException;
    137 
    138     public final boolean isOpen() {
    139         return open;
    140     }
    141 
    142 
    143     // -- Interruption machinery --
    144 
    145     private Interruptible interruptor;
    146     private volatile Thread interrupted;
    147 
    148     /**
    149      * Marks the beginning of an I/O operation that might block indefinitely.
    150      *
    151      * <p> This method should be invoked in tandem with the {@link #end end}
    152      * method, using a <tt>try</tt>&nbsp;...&nbsp;<tt>finally</tt> block as
    153      * shown <a href="#be">above</a>, in order to implement asynchronous
    154      * closing and interruption for this channel.  </p>
    155      */
    156     protected final void begin() {
    157         if (interruptor == null) {
    158             interruptor = new Interruptible() {
    159                     public void interrupt(Thread target) {
    160                         synchronized (closeLock) {
    161                             if (!open)
    162                                 return;
    163                             open = false;
    164                             interrupted = target;
    165                             try {
    166                                 AbstractInterruptibleChannel.this.implCloseChannel();
    167                             } catch (IOException x) { }
    168                         }
    169                     }};
    170         }
    171         blockedOn(interruptor);
    172         Thread me = Thread.currentThread();
    173         if (me.isInterrupted())
    174             interruptor.interrupt(me);
    175     }
    176 
    177     /**
    178      * Marks the end of an I/O operation that might block indefinitely.
    179      *
    180      * <p> This method should be invoked in tandem with the {@link #begin
    181      * begin} method, using a <tt>try</tt>&nbsp;...&nbsp;<tt>finally</tt> block
    182      * as shown <a href="#be">above</a>, in order to implement asynchronous
    183      * closing and interruption for this channel.  </p>
    184      *
    185      * @param  completed
    186      *         <tt>true</tt> if, and only if, the I/O operation completed
    187      *         successfully, that is, had some effect that would be visible to
    188      *         the operation's invoker
    189      *
    190      * @throws  AsynchronousCloseException
    191      *          If the channel was asynchronously closed
    192      *
    193      * @throws  ClosedByInterruptException
    194      *          If the thread blocked in the I/O operation was interrupted
    195      */
    196     protected final void end(boolean completed)
    197         throws AsynchronousCloseException
    198     {
    199         blockedOn(null);
    200         Thread interrupted = this.interrupted;
    201         if (interrupted != null && interrupted == Thread.currentThread()) {
    202             interrupted = null;
    203             throw new ClosedByInterruptException();
    204         }
    205         if (!completed && !open)
    206             throw new AsynchronousCloseException();
    207     }
    208 
    209 
    210     // -- sun.misc.SharedSecrets --
    211     static void blockedOn(Interruptible intr) {         // package-private
    212         // Android-changed: Call Thread.currentThread().blockedOn() directly.
    213         Thread.currentThread().blockedOn(intr);
    214     }
    215 }
    216