Home | History | Annotate | Download | only in ch
      1 /*
      2  * Copyright (c) 2001, 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 sun.nio.ch;
     27 
     28 import java.io.IOException;
     29 import java.nio.channels.*;
     30 import java.nio.channels.spi.*;
     31 
     32 
     33 /**
     34  * An abstract selector impl.
     35  */
     36 
     37 abstract class AbstractPollSelectorImpl
     38     extends SelectorImpl
     39 {
     40 
     41     // The poll fd array
     42     PollArrayWrapper pollWrapper;
     43 
     44     // Initial capacity of the pollfd array
     45     protected final int INIT_CAP = 10;
     46 
     47     // The list of SelectableChannels serviced by this Selector
     48     protected SelectionKeyImpl[] channelArray;
     49 
     50     // In some impls the first entry of channelArray is bogus
     51     protected int channelOffset = 0;
     52 
     53     // The number of valid channels in this Selector's poll array
     54     protected int totalChannels;
     55 
     56     // True if this Selector has been closed
     57     private boolean closed = false;
     58 
     59     // Lock for close and cleanup
     60     private Object closeLock = new Object();
     61 
     62     AbstractPollSelectorImpl(SelectorProvider sp, int channels, int offset) {
     63         super(sp);
     64         this.totalChannels = channels;
     65         this.channelOffset = offset;
     66     }
     67 
     68     public void putEventOps(SelectionKeyImpl sk, int ops) {
     69         synchronized (closeLock) {
     70             if (closed)
     71                 throw new ClosedSelectorException();
     72             pollWrapper.putEventOps(sk.getIndex(), ops);
     73         }
     74     }
     75 
     76     public Selector wakeup() {
     77         pollWrapper.interrupt();
     78         return this;
     79     }
     80 
     81     protected abstract int doSelect(long timeout) throws IOException;
     82 
     83     protected void implClose() throws IOException {
     84         synchronized (closeLock) {
     85             if (closed)
     86                 return;
     87             closed = true;
     88             // Deregister channels
     89             for(int i=channelOffset; i<totalChannels; i++) {
     90                 SelectionKeyImpl ski = channelArray[i];
     91                 assert(ski.getIndex() != -1);
     92                 ski.setIndex(-1);
     93                 deregister(ski);
     94                 SelectableChannel selch = channelArray[i].channel();
     95                 if (!selch.isOpen() && !selch.isRegistered())
     96                     ((SelChImpl)selch).kill();
     97             }
     98             implCloseInterrupt();
     99             pollWrapper.free();
    100             pollWrapper = null;
    101             selectedKeys = null;
    102             channelArray = null;
    103             totalChannels = 0;
    104         }
    105     }
    106 
    107     protected abstract void implCloseInterrupt() throws IOException;
    108 
    109     /**
    110      * Copy the information in the pollfd structs into the opss
    111      * of the corresponding Channels. Add the ready keys to the
    112      * ready queue.
    113      */
    114     protected int updateSelectedKeys() {
    115         int numKeysUpdated = 0;
    116         // Skip zeroth entry; it is for interrupts only
    117         for (int i=channelOffset; i<totalChannels; i++) {
    118             int rOps = pollWrapper.getReventOps(i);
    119             if (rOps != 0) {
    120                 SelectionKeyImpl sk = channelArray[i];
    121                 pollWrapper.putReventOps(i, 0);
    122                 if (selectedKeys.contains(sk)) {
    123                     if (sk.channel.translateAndSetReadyOps(rOps, sk)) {
    124                         numKeysUpdated++;
    125                     }
    126                 } else {
    127                     sk.channel.translateAndSetReadyOps(rOps, sk);
    128                     if ((sk.nioReadyOps() & sk.nioInterestOps()) != 0) {
    129                         selectedKeys.add(sk);
    130                         numKeysUpdated++;
    131                     }
    132                 }
    133             }
    134         }
    135         return numKeysUpdated;
    136     }
    137 
    138     protected void implRegister(SelectionKeyImpl ski) {
    139         synchronized (closeLock) {
    140             if (closed)
    141                 throw new ClosedSelectorException();
    142 
    143             // Check to see if the array is large enough
    144             if (channelArray.length == totalChannels) {
    145                 // Make a larger array
    146                 int newSize = pollWrapper.totalChannels * 2;
    147                 SelectionKeyImpl temp[] = new SelectionKeyImpl[newSize];
    148                 // Copy over
    149                 for (int i=channelOffset; i<totalChannels; i++)
    150                     temp[i] = channelArray[i];
    151                 channelArray = temp;
    152                 // Grow the NativeObject poll array
    153                 pollWrapper.grow(newSize);
    154             }
    155             channelArray[totalChannels] = ski;
    156             ski.setIndex(totalChannels);
    157             pollWrapper.addEntry(ski.channel);
    158             totalChannels++;
    159             keys.add(ski);
    160         }
    161     }
    162 
    163     protected void implDereg(SelectionKeyImpl ski) throws IOException {
    164         // Algorithm: Copy the sc from the end of the list and put it into
    165         // the location of the sc to be removed (since order doesn't
    166         // matter). Decrement the sc count. Update the index of the sc
    167         // that is moved.
    168         int i = ski.getIndex();
    169         assert (i >= 0);
    170         if (i != totalChannels - 1) {
    171             // Copy end one over it
    172             SelectionKeyImpl endChannel = channelArray[totalChannels-1];
    173             channelArray[i] = endChannel;
    174             endChannel.setIndex(i);
    175             pollWrapper.release(i);
    176             PollArrayWrapper.replaceEntry(pollWrapper, totalChannels - 1,
    177                                           pollWrapper, i);
    178         } else {
    179             pollWrapper.release(i);
    180         }
    181         // Destroy the last one
    182         channelArray[totalChannels-1] = null;
    183         totalChannels--;
    184         pollWrapper.totalChannels--;
    185         ski.setIndex(-1);
    186         // Remove the key from keys and selectedKeys
    187         keys.remove(ski);
    188         selectedKeys.remove(ski);
    189         deregister((AbstractSelectionKey)ski);
    190         SelectableChannel selch = ski.channel();
    191         if (!selch.isOpen() && !selch.isRegistered())
    192             ((SelChImpl)selch).kill();
    193     }
    194 }
    195