1 /*
   2  * Copyright (c) 2000, 2011, 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 import java.net.SocketException;
  32 import java.util.*;
  33 
  34 
  35 /**
  36  * Base Selector implementation class.
  37  */
  38 
  39 public abstract class SelectorImpl
  40     extends AbstractSelector
  41 {
  42 
  43     // The set of keys with data ready for an operation
  44     protected Set<SelectionKey> selectedKeys;
  45 
  46     // The set of keys registered with this Selector
  47     protected HashSet<SelectionKey> keys;
  48 
  49     // Public views of the key sets
  50     private Set<SelectionKey> publicKeys;             // Immutable
  51     private Set<SelectionKey> publicSelectedKeys;     // Removal allowed, but not addition
  52 
  53     protected SelectorImpl(SelectorProvider sp) {
  54         super(sp);
  55         keys = new HashSet<SelectionKey>();
  56         selectedKeys = new HashSet<SelectionKey>();
  57         if (Util.atBugLevel("1.4")) {
  58             publicKeys = keys;
  59             publicSelectedKeys = selectedKeys;
  60         } else {
  61             publicKeys = Collections.unmodifiableSet(keys);
  62             publicSelectedKeys = Util.ungrowableSet(selectedKeys);
  63         }
  64     }
  65 
  66     public Set<SelectionKey> keys() {
  67         if (!isOpen() && !Util.atBugLevel("1.4"))
  68             throw new ClosedSelectorException();
  69         return publicKeys;
  70     }
  71 
  72     public Set<SelectionKey> selectedKeys() {
  73         if (!isOpen() && !Util.atBugLevel("1.4"))
  74             throw new ClosedSelectorException();
  75         return publicSelectedKeys;
  76     }
  77 
  78     protected abstract int doSelect(long timeout) throws IOException;
  79 
  80     private int lockAndDoSelect(long timeout) throws IOException {
  81         synchronized (this) {
  82             if (!isOpen())
  83                 throw new ClosedSelectorException();
  84             synchronized (publicKeys) {
  85                 synchronized (publicSelectedKeys) {
  86                     return doSelect(timeout);
  87                 }
  88             }
  89         }
  90     }
  91 
  92     public int select(long timeout)
  93         throws IOException
  94     {
  95         if (timeout < 0)
  96             throw new IllegalArgumentException("Negative timeout");
  97         return lockAndDoSelect((timeout == 0) ? -1 : timeout);
  98     }
  99 
 100     public int select() throws IOException {
 101         return select(0);
 102     }
 103 
 104     public int selectNow() throws IOException {
 105         return lockAndDoSelect(0);
 106     }
 107 
 108     public void implCloseSelector() throws IOException {
 109         wakeup();
 110         synchronized (this) {
 111             synchronized (publicKeys) {
 112                 synchronized (publicSelectedKeys) {
 113                     implClose();
 114                 }
 115             }
 116         }
 117     }
 118 
 119     protected abstract void implClose() throws IOException;
 120 
 121     public void putEventOps(SelectionKeyImpl sk, int ops) { }
 122 
 123     protected final SelectionKey register(AbstractSelectableChannel ch,
 124                                           int ops,
 125                                           Object attachment)
 126     {
 127         if (!(ch instanceof SelChImpl))
 128             throw new IllegalSelectorException();
 129         SelectionKeyImpl k = new SelectionKeyImpl((SelChImpl)ch, this);
 130         k.attach(attachment);
 131         synchronized (publicKeys) {
 132             implRegister(k);
 133         }
 134         k.interestOps(ops);
 135         return k;
 136     }
 137 
 138     protected abstract void implRegister(SelectionKeyImpl ski);
 139 
 140     void processDeregisterQueue() throws IOException {
 141         // Precondition: Synchronized on this, keys, and selectedKeys
 142         Set<SelectionKey> cks = cancelledKeys();
 143         synchronized (cks) {
 144             if (!cks.isEmpty()) {
 145                 Iterator<SelectionKey> i = cks.iterator();
 146                 while (i.hasNext()) {
 147                     SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
 148                     try {
 149                         implDereg(ski);
 150                     } catch (SocketException se) {
 151                         throw new IOException("Error deregistering key", se);
 152                     } finally {
 153                         i.remove();
 154                     }
 155                 }
 156             }
 157         }
 158     }
 159 
 160     protected abstract void implDereg(SelectionKeyImpl ski) throws IOException;
 161 
 162     abstract public Selector wakeup();
 163 
 164 }