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