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 import java.util.*;
  32 import java.util.function.Consumer;
  33 
  34 
  35 /**
  36  * An implementation of Selector for Solaris.
  37  */
  38 class DevPollSelectorImpl
  39     extends SelectorImpl
  40 {
  41 
  42     // File descriptors used for interrupt
  43     protected int fd0;
  44     protected int fd1;
  45 
  46     // The poll object
  47     DevPollArrayWrapper pollWrapper;
  48 
  49     // Maps from file descriptors to keys
  50     private Map<Integer,SelectionKeyImpl> fdToKey;
  51 
  52     // True if this Selector has been closed
  53     private boolean closed = false;
  54 
  55     // Lock for interrupt triggering and clearing
  56     private Object interruptLock = new Object();
  57     private boolean interruptTriggered = false;
  58 
  59     /**
  60      * Package private constructor called by factory method in
  61      * the abstract superclass Selector.
  62      */
  63     DevPollSelectorImpl(SelectorProvider sp) {
  64         super(sp);
  65         long pipeFds = IOUtil.makePipe(false);
  66         fd0 = (int) (pipeFds >>> 32);
  67         fd1 = (int) pipeFds;
  68         pollWrapper = new DevPollArrayWrapper();
  69         pollWrapper.initInterrupt(fd0, fd1);
  70         fdToKey = new HashMap<>();
  71     }
  72 
  73     @Override
  74     protected int doSelect(long timeout) throws IOException {
  75         pollDevPollWrapper(timeout);
  76         try {
  77             return updateSelectedKeys();
  78         } finally {
  79             clearWakeupPipeIfInterrupted();
  80         }
  81     }
  82 
  83     @Override
  84     protected int doSelect(Consumer<SelectionKey> handler, long timeout) throws IOException {
  85         pollDevPollWrapper(timeout);
  86         try {
  87             int entries = pollWrapper.updated;
  88             int numKeysUpdated = 0;
  89             for (int i=0; i<entries; i++) {
  90                 int nextFD = pollWrapper.getDescriptor(i);
  91                 SelectionKeyImpl ski = fdToKey.get(Integer.valueOf(nextFD));
  92                 // ski is null in the case of an interrupt
  93                 if (ski != null) {
  94                     int rOps = pollWrapper.getReventOps(i);
  95                     ski.channel.translateAndSetReadyOps(rOps, ski);
  96                     if (ski.hasOps()) {
  97                         handler.accept(ski);
  98                         numKeysUpdated++;
  99                     }
 100                 }
 101             }
 102             return numKeysUpdated;
 103         } finally {
 104             clearWakeupPipeIfInterrupted();
 105         }
 106     }
 107 
 108     private void clearWakeupPipeIfInterrupted() throws IOException {
 109         if (pollWrapper.interrupted()) {
 110             // Clear the wakeup pipe
 111             pollWrapper.putReventOps(pollWrapper.interruptedIndex(), 0);
 112             synchronized (interruptLock) {
 113                 pollWrapper.clearInterrupted();
 114                 IOUtil.drain(fd0);
 115                 interruptTriggered = false;
 116             }
 117         }
 118     }
 119 
 120     private void pollDevPollWrapper(long timeout) throws ClosedSelectorException, IOException {
 121         if (closed)
 122             throw new ClosedSelectorException();
 123         processDeregisterQueue();
 124         try {
 125             begin();
 126             pollWrapper.poll(timeout);
 127         } finally {
 128             end();
 129         }
 130         processDeregisterQueue();
 131     }
 132 
 133     /**
 134      * Update the keys whose fd's have been selected by the devpoll
 135      * driver. Add the ready keys to the ready queue.
 136      */
 137     private int updateSelectedKeys() {
 138         int entries = pollWrapper.updated;
 139         int numKeysUpdated = 0;
 140         for (int i=0; i<entries; i++) {
 141             int nextFD = pollWrapper.getDescriptor(i);
 142             SelectionKeyImpl ski = fdToKey.get(Integer.valueOf(nextFD));
 143             // ski is null in the case of an interrupt
 144             if (ski != null) {
 145                 int rOps = pollWrapper.getReventOps(i);
 146                 if (selectedKeys.contains(ski)) {
 147                     if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
 148                         numKeysUpdated++;
 149                     }
 150                 } else {
 151                     ski.channel.translateAndSetReadyOps(rOps, ski);
 152                     if (ski.hasOps()) {
 153                         selectedKeys.add(ski);
 154                         numKeysUpdated++;
 155                     }
 156                 }
 157             }
 158         }
 159         return numKeysUpdated;
 160     }
 161 
 162     protected void implClose() throws IOException {
 163         if (closed)
 164             return;
 165         closed = true;
 166 
 167         // prevent further wakeup
 168         synchronized (interruptLock) {
 169             interruptTriggered = true;
 170         }
 171 
 172         FileDispatcherImpl.closeIntFD(fd0);
 173         FileDispatcherImpl.closeIntFD(fd1);
 174 
 175         pollWrapper.release(fd0);
 176         pollWrapper.closeDevPollFD();
 177         selectedKeys = null;
 178 
 179         // Deregister channels
 180         Iterator<SelectionKey> i = keys.iterator();
 181         while (i.hasNext()) {
 182             SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
 183             deregister(ski);
 184             SelectableChannel selch = ski.channel();
 185             if (!selch.isOpen() && !selch.isRegistered())
 186                 ((SelChImpl)selch).kill();
 187             i.remove();
 188         }
 189         fd0 = -1;
 190         fd1 = -1;
 191     }
 192 
 193     protected void implRegister(SelectionKeyImpl ski) {
 194         int fd = IOUtil.fdVal(ski.channel.getFD());
 195         fdToKey.put(Integer.valueOf(fd), ski);
 196         keys.add(ski);
 197     }
 198 
 199     protected void implDereg(SelectionKeyImpl ski) throws IOException {
 200         int i = ski.getIndex();
 201         assert (i >= 0);
 202         int fd = ski.channel.getFDVal();
 203         fdToKey.remove(Integer.valueOf(fd));
 204         pollWrapper.release(fd);
 205         ski.setIndex(-1);
 206         keys.remove(ski);
 207         selectedKeys.remove(ski);
 208         deregister((AbstractSelectionKey)ski);
 209         SelectableChannel selch = ski.channel();
 210         if (!selch.isOpen() && !selch.isRegistered())
 211             ((SelChImpl)selch).kill();
 212     }
 213 
 214     public void putEventOps(SelectionKeyImpl sk, int ops) {
 215         if (closed)
 216             throw new ClosedSelectorException();
 217         int fd = IOUtil.fdVal(sk.channel.getFD());
 218         pollWrapper.setInterest(fd, ops);
 219     }
 220 
 221     public Selector wakeup() {
 222         synchronized (interruptLock) {
 223             if (!interruptTriggered) {
 224                 pollWrapper.interrupt();
 225                 interruptTriggered = true;
 226             }
 227         }
 228         return this;
 229     }
 230 }