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