< prev index next >

src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java

Print this page
rev 49242 : [mq]: selector-cleanup
   1 /*
   2  * Copyright (c) 2011, 2015, 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 /*
  27  * KQueueSelectorImpl.java
  28  * Implementation of Selector using FreeBSD / Mac OS X kqueues
  29  * Derived from Sun's DevPollSelectorImpl
  30  */
  31 
  32 package sun.nio.ch;
  33 
  34 import java.io.IOException;
  35 import java.io.FileDescriptor;
  36 import java.nio.channels.*;
  37 import java.nio.channels.spi.*;
  38 import java.util.*;



  39 
  40 class KQueueSelectorImpl
  41     extends SelectorImpl
  42 {
  43     // File descriptors used for interrupt
  44     protected int fd0;
  45     protected int fd1;
  46 
  47     // The kqueue manipulator
  48     KQueueArrayWrapper kqueueWrapper;
  49 
  50     // Count of registered descriptors (including interrupt)
  51     private int totalChannels;
  52 
  53     // Map from a file descriptor to an entry containing the selection key
  54     private HashMap<Integer,MapEntry> fdMap;
  55 
  56     // True if this Selector has been closed
  57     private boolean closed = false;
  58 
  59     // Lock for interrupt triggering and clearing
  60     private Object interruptLock = new Object();
  61     private boolean interruptTriggered = false;
  62 
  63     // used by updateSelectedKeys to handle cases where the same file
  64     // descriptor is polled by more than one filter
  65     private long updateCount;
  66 
  67     // Used to map file descriptors to a selection key and "update count"
  68     // (see updateSelectedKeys for usage).
  69     private static class MapEntry {
  70         SelectionKeyImpl ski;
  71         long updateCount;
  72         MapEntry(SelectionKeyImpl ski) {
  73             this.ski = ski;
  74         }
  75     }
  76 
  77     /**
  78      * Package private constructor called by factory method in
  79      * the abstract superclass Selector.
  80      */
  81     KQueueSelectorImpl(SelectorProvider sp) {
  82         super(sp);
  83         long fds = IOUtil.makePipe(false);
  84         fd0 = (int)(fds >>> 32);
  85         fd1 = (int)fds;
  86         try {
  87             kqueueWrapper = new KQueueArrayWrapper();
  88             kqueueWrapper.initInterrupt(fd0, fd1);
  89             fdMap = new HashMap<>();
  90             totalChannels = 1;
  91         } catch (Throwable t) {
  92             try {
  93                 FileDispatcherImpl.closeIntFD(fd0);
  94             } catch (IOException ioe0) {
  95                 t.addSuppressed(ioe0);
  96             }
  97             try {
  98                 FileDispatcherImpl.closeIntFD(fd1);
  99             } catch (IOException ioe1) {
 100                 t.addSuppressed(ioe1);
 101             }
 102             throw t;
 103         }
 104     }
 105 




 106 

 107     protected int doSelect(long timeout)
 108         throws IOException
 109     {
 110         int entries = 0;
 111         if (closed)
 112             throw new ClosedSelectorException();
 113         processDeregisterQueue();
 114         try {
 115             begin();
 116             entries = kqueueWrapper.poll(timeout);
 117         } finally {
 118             end();
 119         }
 120         processDeregisterQueue();
 121         return updateSelectedKeys(entries);
 122     }
 123 
 124     /**
 125      * Update the keys whose fd's have been selected by kqueue.
 126      * Add the ready keys to the selected key set.
 127      * If the interrupt fd has been selected, drain it and clear the interrupt.
 128      */
 129     private int updateSelectedKeys(int entries)
 130         throws IOException
 131     {
 132         int numKeysUpdated = 0;
 133         boolean interrupted = false;
 134 
 135         // A file descriptor may be registered with kqueue with more than one
 136         // filter and so there may be more than one event for a fd. The update
 137         // count in the MapEntry tracks when the fd was last updated and this
 138         // ensures that the ready ops are updated rather than replaced by a
 139         // second or subsequent event.
 140         updateCount++;
 141 
 142         for (int i = 0; i < entries; i++) {
 143             int nextFD = kqueueWrapper.getDescriptor(i);
 144             if (nextFD == fd0) {
 145                 interrupted = true;
 146             } else {
 147                 MapEntry me = fdMap.get(Integer.valueOf(nextFD));
 148 
 149                 // entry is null in the case of an interrupt
 150                 if (me != null) {
 151                     int rOps = kqueueWrapper.getReventOps(i);
 152                     SelectionKeyImpl ski = me.ski;
 153                     if (selectedKeys.contains(ski)) {
 154                         // first time this file descriptor has been encountered on this
 155                         // update?
 156                         if (me.updateCount != updateCount) {
 157                             if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
 158                                 numKeysUpdated++;
 159                                 me.updateCount = updateCount;
 160                             }
 161                         } else {
 162                             // ready ops have already been set on this update
 163                             ski.channel.translateAndUpdateReadyOps(rOps, ski);
 164                         }
 165                     } else {
 166                         ski.channel.translateAndSetReadyOps(rOps, ski);
 167                         if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {
 168                             selectedKeys.add(ski);
 169                             numKeysUpdated++;
 170                             me.updateCount = updateCount;
 171                         }
 172                     }
 173                 }
 174             }
 175         }
 176 
 177         if (interrupted) {
 178             // Clear the wakeup pipe
 179             synchronized (interruptLock) {
 180                 IOUtil.drain(fd0);
 181                 interruptTriggered = false;
 182             }
 183         }
 184         return numKeysUpdated;
 185     }
 186 
 187 
 188     protected void implClose() throws IOException {
 189         if (!closed) {
 190             closed = true;
 191 
 192             // prevent further wakeup
 193             synchronized (interruptLock) {
 194                 interruptTriggered = true;
 195             }
 196 

 197             FileDispatcherImpl.closeIntFD(fd0);
 198             FileDispatcherImpl.closeIntFD(fd1);
 199             if (kqueueWrapper != null) {
 200                 kqueueWrapper.close();
 201                 kqueueWrapper = null;
 202                 selectedKeys = null;
 203 
 204                 // Deregister channels
 205                 Iterator<SelectionKey> i = keys.iterator();
 206                 while (i.hasNext()) {
 207                     SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
 208                     deregister(ski);
 209                     SelectableChannel selch = ski.channel();
 210                     if (!selch.isOpen() && !selch.isRegistered())
 211                         ((SelChImpl)selch).kill();
 212                     i.remove();
 213                 }
 214                 totalChannels = 0;
 215             }
 216             fd0 = -1;
 217             fd1 = -1;
 218         }
 219     }
 220 
 221 
 222     protected void implRegister(SelectionKeyImpl ski) {
 223         if (closed)
 224             throw new ClosedSelectorException();
 225         int fd = IOUtil.fdVal(ski.channel.getFD());
 226         fdMap.put(Integer.valueOf(fd), new MapEntry(ski));
 227         totalChannels++;
 228         keys.add(ski);
 229     }
 230 
 231 
 232     protected void implDereg(SelectionKeyImpl ski) throws IOException {
 233         int fd = ski.channel.getFDVal();
 234         fdMap.remove(Integer.valueOf(fd));
 235         kqueueWrapper.release(ski.channel);
 236         totalChannels--;
 237         keys.remove(ski);
 238         selectedKeys.remove(ski);
 239         deregister((AbstractSelectionKey)ski);
 240         SelectableChannel selch = ski.channel();
 241         if (!selch.isOpen() && !selch.isRegistered())
 242             ((SelChImpl)selch).kill();
 243     }
 244 
 245 
 246     public void putEventOps(SelectionKeyImpl ski, int ops) {
 247         if (closed)
 248             throw new ClosedSelectorException();
 249         kqueueWrapper.setInterest(ski.channel, ops);
 250     }
 251 
 252 
 253     public Selector wakeup() {
 254         synchronized (interruptLock) {
 255             if (!interruptTriggered) {
 256                 kqueueWrapper.interrupt();
 257                 interruptTriggered = true;
 258             }
 259         }
 260         return this;
 261     }







 262 }
   1 /*
   2  * Copyright (c) 2011, 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 /*
  27  * KQueueSelectorImpl.java
  28  * Implementation of Selector using FreeBSD / Mac OS X kqueues

  29  */
  30 
  31 package sun.nio.ch;
  32 
  33 import java.io.IOException;
  34 import java.nio.channels.ClosedSelectorException;
  35 import java.nio.channels.SelectableChannel;
  36 import java.nio.channels.SelectionKey;
  37 import java.nio.channels.Selector;
  38 import java.nio.channels.spi.SelectorProvider;
  39 import java.util.HashMap;
  40 import java.util.Iterator;
  41 
  42 class KQueueSelectorImpl
  43     extends SelectorImpl
  44 {
  45     // File descriptors used for interrupt
  46     private final int fd0;
  47     private final int fd1;
  48 
  49     // The kqueue manipulator
  50     private final KQueueArrayWrapper kqueueWrapper;



  51 
  52     // Map from a file descriptor to an entry containing the selection key
  53     private final HashMap<Integer, MapEntry> fdMap;
  54 
  55     // True if this Selector has been closed
  56     private boolean closed;
  57 
  58     // Lock for interrupt triggering and clearing
  59     private final Object interruptLock = new Object();
  60     private boolean interruptTriggered;
  61 
  62     // used by updateSelectedKeys to handle cases where the same file
  63     // descriptor is polled by more than one filter
  64     private long updateCount;
  65 
  66     // Used to map file descriptors to a selection key and "update count"
  67     // (see updateSelectedKeys for usage).
  68     private static class MapEntry {
  69         SelectionKeyImpl ski;
  70         long updateCount;
  71         MapEntry(SelectionKeyImpl ski) {
  72             this.ski = ski;
  73         }
  74     }
  75 
  76     /**
  77      * Package private constructor called by factory method in
  78      * the abstract superclass Selector.
  79      */
  80     KQueueSelectorImpl(SelectorProvider sp) throws IOException {
  81         super(sp);
  82         long fds = IOUtil.makePipe(false);
  83         fd0 = (int)(fds >>> 32);
  84         fd1 = (int)fds;
  85         try {
  86             kqueueWrapper = new KQueueArrayWrapper(fd0, fd1);

  87             fdMap = new HashMap<>();

  88         } catch (Throwable t) {
  89             try {
  90                 FileDispatcherImpl.closeIntFD(fd0);
  91             } catch (IOException ioe0) {
  92                 t.addSuppressed(ioe0);
  93             }
  94             try {
  95                 FileDispatcherImpl.closeIntFD(fd1);
  96             } catch (IOException ioe1) {
  97                 t.addSuppressed(ioe1);
  98             }
  99             throw t;
 100         }
 101     }
 102 
 103     private void ensureOpen() {
 104         if (closed)
 105             throw new ClosedSelectorException();
 106     }
 107 
 108     @Override
 109     protected int doSelect(long timeout)
 110         throws IOException
 111     {
 112         ensureOpen();
 113         int numEntries;

 114         processDeregisterQueue();
 115         try {
 116             begin();
 117             numEntries = kqueueWrapper.poll(timeout);
 118         } finally {
 119             end();
 120         }
 121         processDeregisterQueue();
 122         return updateSelectedKeys(numEntries);
 123     }
 124 
 125     /**
 126      * Update the keys whose fd's have been selected by kqueue.
 127      * Add the ready keys to the selected key set.
 128      * If the interrupt fd has been selected, drain it and clear the interrupt.
 129      */
 130     private int updateSelectedKeys(int numEntries)
 131         throws IOException
 132     {
 133         int numKeysUpdated = 0;
 134         boolean interrupted = false;
 135 
 136         // A file descriptor may be registered with kqueue with more than one
 137         // filter and so there may be more than one event for a fd. The update
 138         // count in the MapEntry tracks when the fd was last updated and this
 139         // ensures that the ready ops are updated rather than replaced by a
 140         // second or subsequent event.
 141         updateCount++;
 142 
 143         for (int i = 0; i < numEntries; i++) {
 144             int nextFD = kqueueWrapper.getDescriptor(i);
 145             if (nextFD == fd0) {
 146                 interrupted = true;
 147             } else {
 148                 MapEntry me = fdMap.get(Integer.valueOf(nextFD));


 149                 if (me != null) {
 150                     int rOps = kqueueWrapper.getReventOps(i);
 151                     SelectionKeyImpl ski = me.ski;
 152                     if (selectedKeys.contains(ski)) {
 153                         // first time this file descriptor has been encountered on this
 154                         // update?
 155                         if (me.updateCount != updateCount) {
 156                             if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
 157                                 numKeysUpdated++;
 158                                 me.updateCount = updateCount;
 159                             }
 160                         } else {
 161                             // ready ops have already been set on this update
 162                             ski.channel.translateAndUpdateReadyOps(rOps, ski);
 163                         }
 164                     } else {
 165                         ski.channel.translateAndSetReadyOps(rOps, ski);
 166                         if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {
 167                             selectedKeys.add(ski);
 168                             numKeysUpdated++;
 169                             me.updateCount = updateCount;
 170                         }
 171                     }
 172                 }
 173             }
 174         }
 175 
 176         if (interrupted) {
 177             clearInterrupt();




 178         }
 179         return numKeysUpdated;
 180     }
 181 
 182     @Override
 183     protected void implClose() throws IOException {
 184         if (!closed) {
 185             closed = true;
 186 
 187             // prevent further wakeup
 188             synchronized (interruptLock) {
 189                 interruptTriggered = true;
 190             }
 191 
 192             kqueueWrapper.close();
 193             FileDispatcherImpl.closeIntFD(fd0);
 194             FileDispatcherImpl.closeIntFD(fd1);




 195 
 196             // Deregister channels
 197             Iterator<SelectionKey> i = keys.iterator();
 198             while (i.hasNext()) {
 199                 SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
 200                 deregister(ski);
 201                 SelectableChannel selch = ski.channel();
 202                 if (!selch.isOpen() && !selch.isRegistered())
 203                     ((SelChImpl)selch).kill();
 204                 i.remove();
 205             }




 206         }
 207     }
 208 
 209     @Override
 210     protected void implRegister(SelectionKeyImpl ski) {
 211         ensureOpen();

 212         int fd = IOUtil.fdVal(ski.channel.getFD());
 213         fdMap.put(Integer.valueOf(fd), new MapEntry(ski));

 214         keys.add(ski);
 215     }
 216 
 217     @Override
 218     protected void implDereg(SelectionKeyImpl ski) throws IOException {
 219         int fd = ski.channel.getFDVal();
 220         fdMap.remove(Integer.valueOf(fd));
 221         kqueueWrapper.release(ski.channel);

 222         keys.remove(ski);
 223         selectedKeys.remove(ski);
 224         deregister(ski);
 225         SelectableChannel selch = ski.channel();
 226         if (!selch.isOpen() && !selch.isRegistered())
 227             ((SelChImpl)selch).kill();
 228     }
 229 
 230     @Override
 231     public void putEventOps(SelectionKeyImpl ski, int ops) {
 232         ensureOpen();

 233         kqueueWrapper.setInterest(ski.channel, ops);
 234     }
 235 
 236     @Override
 237     public Selector wakeup() {
 238         synchronized (interruptLock) {
 239             if (!interruptTriggered) {
 240                 kqueueWrapper.interrupt();
 241                 interruptTriggered = true;
 242             }
 243         }
 244         return this;
 245     }
 246 
 247     private void clearInterrupt() throws IOException {
 248         synchronized (interruptLock) {
 249             IOUtil.drain(fd0);
 250             interruptTriggered = false;
 251         }
 252     }
 253 }
< prev index next >