src/java.base/share/classes/java/nio/channels/spi/AbstractSelectableChannel.java
changeset 47216 71c04702a3d5
parent 32143 394ab6a6658d
child 48761 74c1fa26435a
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     1 /*
       
     2  * Copyright (c) 2000, 2013, 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 package java.nio.channels.spi;
       
    27 
       
    28 import java.io.IOException;
       
    29 import java.nio.channels.*;
       
    30 
       
    31 
       
    32 /**
       
    33  * Base implementation class for selectable channels.
       
    34  *
       
    35  * <p> This class defines methods that handle the mechanics of channel
       
    36  * registration, deregistration, and closing.  It maintains the current
       
    37  * blocking mode of this channel as well as its current set of selection keys.
       
    38  * It performs all of the synchronization required to implement the {@link
       
    39  * java.nio.channels.SelectableChannel} specification.  Implementations of the
       
    40  * abstract protected methods defined in this class need not synchronize
       
    41  * against other threads that might be engaged in the same operations.  </p>
       
    42  *
       
    43  *
       
    44  * @author Mark Reinhold
       
    45  * @author Mike McCloskey
       
    46  * @author JSR-51 Expert Group
       
    47  * @since 1.4
       
    48  */
       
    49 
       
    50 public abstract class AbstractSelectableChannel
       
    51     extends SelectableChannel
       
    52 {
       
    53 
       
    54     // The provider that created this channel
       
    55     private final SelectorProvider provider;
       
    56 
       
    57     // Keys that have been created by registering this channel with selectors.
       
    58     // They are saved because if this channel is closed the keys must be
       
    59     // deregistered.  Protected by keyLock.
       
    60     //
       
    61     private SelectionKey[] keys = null;
       
    62     private int keyCount = 0;
       
    63 
       
    64     // Lock for key set and count
       
    65     private final Object keyLock = new Object();
       
    66 
       
    67     // Lock for registration and configureBlocking operations
       
    68     private final Object regLock = new Object();
       
    69 
       
    70     // Blocking mode, protected by regLock
       
    71     boolean blocking = true;
       
    72 
       
    73     /**
       
    74      * Initializes a new instance of this class.
       
    75      *
       
    76      * @param  provider
       
    77      *         The provider that created this channel
       
    78      */
       
    79     protected AbstractSelectableChannel(SelectorProvider provider) {
       
    80         this.provider = provider;
       
    81     }
       
    82 
       
    83     /**
       
    84      * Returns the provider that created this channel.
       
    85      *
       
    86      * @return  The provider that created this channel
       
    87      */
       
    88     public final SelectorProvider provider() {
       
    89         return provider;
       
    90     }
       
    91 
       
    92 
       
    93     // -- Utility methods for the key set --
       
    94 
       
    95     private void addKey(SelectionKey k) {
       
    96         assert Thread.holdsLock(keyLock);
       
    97         int i = 0;
       
    98         if ((keys != null) && (keyCount < keys.length)) {
       
    99             // Find empty element of key array
       
   100             for (i = 0; i < keys.length; i++)
       
   101                 if (keys[i] == null)
       
   102                     break;
       
   103         } else if (keys == null) {
       
   104             keys =  new SelectionKey[3];
       
   105         } else {
       
   106             // Grow key array
       
   107             int n = keys.length * 2;
       
   108             SelectionKey[] ks =  new SelectionKey[n];
       
   109             for (i = 0; i < keys.length; i++)
       
   110                 ks[i] = keys[i];
       
   111             keys = ks;
       
   112             i = keyCount;
       
   113         }
       
   114         keys[i] = k;
       
   115         keyCount++;
       
   116     }
       
   117 
       
   118     private SelectionKey findKey(Selector sel) {
       
   119         synchronized (keyLock) {
       
   120             if (keys == null)
       
   121                 return null;
       
   122             for (int i = 0; i < keys.length; i++)
       
   123                 if ((keys[i] != null) && (keys[i].selector() == sel))
       
   124                     return keys[i];
       
   125             return null;
       
   126         }
       
   127     }
       
   128 
       
   129     void removeKey(SelectionKey k) {                    // package-private
       
   130         synchronized (keyLock) {
       
   131             for (int i = 0; i < keys.length; i++)
       
   132                 if (keys[i] == k) {
       
   133                     keys[i] = null;
       
   134                     keyCount--;
       
   135                 }
       
   136             ((AbstractSelectionKey)k).invalidate();
       
   137         }
       
   138     }
       
   139 
       
   140     private boolean haveValidKeys() {
       
   141         synchronized (keyLock) {
       
   142             if (keyCount == 0)
       
   143                 return false;
       
   144             for (int i = 0; i < keys.length; i++) {
       
   145                 if ((keys[i] != null) && keys[i].isValid())
       
   146                     return true;
       
   147             }
       
   148             return false;
       
   149         }
       
   150     }
       
   151 
       
   152 
       
   153     // -- Registration --
       
   154 
       
   155     public final boolean isRegistered() {
       
   156         synchronized (keyLock) {
       
   157             return keyCount != 0;
       
   158         }
       
   159     }
       
   160 
       
   161     public final SelectionKey keyFor(Selector sel) {
       
   162         return findKey(sel);
       
   163     }
       
   164 
       
   165     /**
       
   166      * Registers this channel with the given selector, returning a selection key.
       
   167      *
       
   168      * <p>  This method first verifies that this channel is open and that the
       
   169      * given initial interest set is valid.
       
   170      *
       
   171      * <p> If this channel is already registered with the given selector then
       
   172      * the selection key representing that registration is returned after
       
   173      * setting its interest set to the given value.
       
   174      *
       
   175      * <p> Otherwise this channel has not yet been registered with the given
       
   176      * selector, so the {@link AbstractSelector#register register} method of
       
   177      * the selector is invoked while holding the appropriate locks.  The
       
   178      * resulting key is added to this channel's key set before being returned.
       
   179      * </p>
       
   180      *
       
   181      * @throws  ClosedSelectorException {@inheritDoc}
       
   182      *
       
   183      * @throws  IllegalBlockingModeException {@inheritDoc}
       
   184      *
       
   185      * @throws  IllegalSelectorException {@inheritDoc}
       
   186      *
       
   187      * @throws  CancelledKeyException {@inheritDoc}
       
   188      *
       
   189      * @throws  IllegalArgumentException {@inheritDoc}
       
   190      */
       
   191     public final SelectionKey register(Selector sel, int ops,
       
   192                                        Object att)
       
   193         throws ClosedChannelException
       
   194     {
       
   195         synchronized (regLock) {
       
   196             if (!isOpen())
       
   197                 throw new ClosedChannelException();
       
   198             if ((ops & ~validOps()) != 0)
       
   199                 throw new IllegalArgumentException();
       
   200             if (blocking)
       
   201                 throw new IllegalBlockingModeException();
       
   202             SelectionKey k = findKey(sel);
       
   203             if (k != null) {
       
   204                 k.interestOps(ops);
       
   205                 k.attach(att);
       
   206             }
       
   207             if (k == null) {
       
   208                 // New registration
       
   209                 synchronized (keyLock) {
       
   210                     if (!isOpen())
       
   211                         throw new ClosedChannelException();
       
   212                     k = ((AbstractSelector)sel).register(this, ops, att);
       
   213                     addKey(k);
       
   214                 }
       
   215             }
       
   216             return k;
       
   217         }
       
   218     }
       
   219 
       
   220 
       
   221     // -- Closing --
       
   222 
       
   223     /**
       
   224      * Closes this channel.
       
   225      *
       
   226      * <p> This method, which is specified in the {@link
       
   227      * AbstractInterruptibleChannel} class and is invoked by the {@link
       
   228      * java.nio.channels.Channel#close close} method, in turn invokes the
       
   229      * {@link #implCloseSelectableChannel implCloseSelectableChannel} method in
       
   230      * order to perform the actual work of closing this channel.  It then
       
   231      * cancels all of this channel's keys.  </p>
       
   232      */
       
   233     protected final void implCloseChannel() throws IOException {
       
   234         implCloseSelectableChannel();
       
   235         synchronized (keyLock) {
       
   236             int count = (keys == null) ? 0 : keys.length;
       
   237             for (int i = 0; i < count; i++) {
       
   238                 SelectionKey k = keys[i];
       
   239                 if (k != null)
       
   240                     k.cancel();
       
   241             }
       
   242         }
       
   243     }
       
   244 
       
   245     /**
       
   246      * Closes this selectable channel.
       
   247      *
       
   248      * <p> This method is invoked by the {@link java.nio.channels.Channel#close
       
   249      * close} method in order to perform the actual work of closing the
       
   250      * channel.  This method is only invoked if the channel has not yet been
       
   251      * closed, and it is never invoked more than once.
       
   252      *
       
   253      * <p> An implementation of this method must arrange for any other thread
       
   254      * that is blocked in an I/O operation upon this channel to return
       
   255      * immediately, either by throwing an exception or by returning normally.
       
   256      * </p>
       
   257      *
       
   258      * @throws  IOException
       
   259      *          If an I/O error occurs
       
   260      */
       
   261     protected abstract void implCloseSelectableChannel() throws IOException;
       
   262 
       
   263 
       
   264     // -- Blocking --
       
   265 
       
   266     public final boolean isBlocking() {
       
   267         synchronized (regLock) {
       
   268             return blocking;
       
   269         }
       
   270     }
       
   271 
       
   272     public final Object blockingLock() {
       
   273         return regLock;
       
   274     }
       
   275 
       
   276     /**
       
   277      * Adjusts this channel's blocking mode.
       
   278      *
       
   279      * <p> If the given blocking mode is different from the current blocking
       
   280      * mode then this method invokes the {@link #implConfigureBlocking
       
   281      * implConfigureBlocking} method, while holding the appropriate locks, in
       
   282      * order to change the mode.  </p>
       
   283      */
       
   284     public final SelectableChannel configureBlocking(boolean block)
       
   285         throws IOException
       
   286     {
       
   287         synchronized (regLock) {
       
   288             if (!isOpen())
       
   289                 throw new ClosedChannelException();
       
   290             if (blocking == block)
       
   291                 return this;
       
   292             if (block && haveValidKeys())
       
   293                 throw new IllegalBlockingModeException();
       
   294             implConfigureBlocking(block);
       
   295             blocking = block;
       
   296         }
       
   297         return this;
       
   298     }
       
   299 
       
   300     /**
       
   301      * Adjusts this channel's blocking mode.
       
   302      *
       
   303      * <p> This method is invoked by the {@link #configureBlocking
       
   304      * configureBlocking} method in order to perform the actual work of
       
   305      * changing the blocking mode.  This method is only invoked if the new mode
       
   306      * is different from the current mode.  </p>
       
   307      *
       
   308      * @param  block  If {@code true} then this channel will be placed in
       
   309      *                blocking mode; if {@code false} then it will be placed
       
   310      *                non-blocking mode
       
   311      *
       
   312      * @throws IOException
       
   313      *         If an I/O error occurs
       
   314      */
       
   315     protected abstract void implConfigureBlocking(boolean block)
       
   316         throws IOException;
       
   317 
       
   318 }