Home | History | Annotate | Download | only in ch
      1 /*
      2  * Copyright (c) 2008, 2009, 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 sun.nio.ch;
     27 
     28 import java.nio.channels.spi.AsynchronousChannelProvider;
     29 import java.nio.channels.*;
     30 import java.io.IOException;
     31 import java.io.Closeable;
     32 import java.io.FileDescriptor;
     33 import java.util.Map;
     34 import java.util.HashMap;
     35 import java.util.concurrent.locks.ReadWriteLock;
     36 import java.util.concurrent.locks.ReentrantReadWriteLock;
     37 
     38 /**
     39  * Base implementation of AsynchronousChannelGroupImpl for Unix systems.
     40  */
     41 
     42 abstract class Port extends AsynchronousChannelGroupImpl {
     43 
     44     /**
     45      * Implemented by clients registered with this port.
     46      */
     47     interface PollableChannel extends Closeable {
     48         void onEvent(int events, boolean mayInvokeDirect);
     49     }
     50 
     51     // maps fd to "pollable" channel
     52     protected final ReadWriteLock fdToChannelLock = new ReentrantReadWriteLock();
     53     protected final Map<Integer,PollableChannel> fdToChannel =
     54         new HashMap<Integer,PollableChannel>();
     55 
     56 
     57     Port(AsynchronousChannelProvider provider, ThreadPool pool) {
     58         super(provider, pool);
     59     }
     60 
     61     /**
     62      * Register channel identified by its file descriptor
     63      */
     64     final void register(int fd, PollableChannel ch) {
     65         fdToChannelLock.writeLock().lock();
     66         try {
     67             if (isShutdown())
     68                 throw new ShutdownChannelGroupException();
     69             fdToChannel.put(Integer.valueOf(fd), ch);
     70         } finally {
     71             fdToChannelLock.writeLock().unlock();
     72         }
     73     }
     74 
     75     /**
     76      * Callback method for implementations that need special handling when fd is
     77      * removed (currently only needed in the AIX-Port - see AixPollPort.java).
     78      */
     79     protected void preUnregister(int fd) {
     80         // Do nothing by default.
     81     }
     82 
     83     /**
     84      * Unregister channel identified by its file descriptor
     85      */
     86     final void unregister(int fd) {
     87         boolean checkForShutdown = false;
     88 
     89         preUnregister(fd);
     90 
     91         fdToChannelLock.writeLock().lock();
     92         try {
     93             fdToChannel.remove(Integer.valueOf(fd));
     94 
     95             // last key to be removed so check if group is shutdown
     96             if (fdToChannel.isEmpty())
     97                 checkForShutdown = true;
     98 
     99         } finally {
    100             fdToChannelLock.writeLock().unlock();
    101         }
    102 
    103         // continue shutdown
    104         if (checkForShutdown && isShutdown()) {
    105             try {
    106                 shutdownNow();
    107             } catch (IOException ignore) { }
    108         }
    109     }
    110     /**
    111      * Register file descriptor with polling mechanism for given events.
    112      * The implementation should translate the events as required.
    113      */
    114     abstract void startPoll(int fd, int events);
    115 
    116     @Override
    117     final boolean isEmpty() {
    118         fdToChannelLock.writeLock().lock();
    119         try {
    120             return fdToChannel.isEmpty();
    121         } finally {
    122             fdToChannelLock.writeLock().unlock();
    123         }
    124     }
    125 
    126     @Override
    127     final Object attachForeignChannel(final Channel channel, FileDescriptor fd) {
    128         int fdVal = IOUtil.fdVal(fd);
    129         register(fdVal, new PollableChannel() {
    130             public void onEvent(int events, boolean mayInvokeDirect) { }
    131             public void close() throws IOException {
    132                 channel.close();
    133             }
    134         });
    135         return Integer.valueOf(fdVal);
    136     }
    137 
    138     @Override
    139     final void detachForeignChannel(Object key) {
    140         unregister((Integer)key);
    141     }
    142 
    143     @Override
    144     final void closeAllChannels() {
    145         /**
    146          * Close channels in batches of up to 128 channels. This allows close
    147          * to remove the channel from the map without interference.
    148          */
    149         final int MAX_BATCH_SIZE = 128;
    150         PollableChannel channels[] = new PollableChannel[MAX_BATCH_SIZE];
    151         int count;
    152         do {
    153             // grab a batch of up to 128 channels
    154             fdToChannelLock.writeLock().lock();
    155             count = 0;
    156             try {
    157                 for (Integer fd: fdToChannel.keySet()) {
    158                     channels[count++] = fdToChannel.get(fd);
    159                     if (count >= MAX_BATCH_SIZE)
    160                         break;
    161                 }
    162             } finally {
    163                 fdToChannelLock.writeLock().unlock();
    164             }
    165 
    166             // close them
    167             for (int i=0; i<count; i++) {
    168                 try {
    169                     channels[i].close();
    170                 } catch (IOException ignore) { }
    171             }
    172         } while (count > 0);
    173     }
    174 }
    175