Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java
38829 views
/*1* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425/*26* KQueueSelectorImpl.java27* Implementation of Selector using FreeBSD / Mac OS X kqueues28* Derived from Sun's DevPollSelectorImpl29*/3031package sun.nio.ch;3233import java.io.IOException;34import java.io.FileDescriptor;35import java.nio.channels.*;36import java.nio.channels.spi.*;37import java.util.*;38import sun.misc.*;3940class KQueueSelectorImpl41extends SelectorImpl42{43// File descriptors used for interrupt44protected int fd0;45protected int fd1;4647// The kqueue manipulator48KQueueArrayWrapper kqueueWrapper;4950// Count of registered descriptors (including interrupt)51private int totalChannels;5253// Map from a file descriptor to an entry containing the selection key54private HashMap<Integer,MapEntry> fdMap;5556// True if this Selector has been closed57private boolean closed = false;5859// Lock for interrupt triggering and clearing60private Object interruptLock = new Object();61private boolean interruptTriggered = false;6263// used by updateSelectedKeys to handle cases where the same file64// descriptor is polled by more than one filter65private long updateCount;6667// Used to map file descriptors to a selection key and "update count"68// (see updateSelectedKeys for usage).69private static class MapEntry {70SelectionKeyImpl ski;71long updateCount;72MapEntry(SelectionKeyImpl ski) {73this.ski = ski;74}75}7677/**78* Package private constructor called by factory method in79* the abstract superclass Selector.80*/81KQueueSelectorImpl(SelectorProvider sp) {82super(sp);83long fds = IOUtil.makePipe(false);84fd0 = (int)(fds >>> 32);85fd1 = (int)fds;86try {87kqueueWrapper = new KQueueArrayWrapper();88kqueueWrapper.initInterrupt(fd0, fd1);89fdMap = new HashMap<>();90totalChannels = 1;91} catch (Throwable t) {92try {93FileDispatcherImpl.closeIntFD(fd0);94} catch (IOException ioe0) {95t.addSuppressed(ioe0);96}97try {98FileDispatcherImpl.closeIntFD(fd1);99} catch (IOException ioe1) {100t.addSuppressed(ioe1);101}102throw t;103}104}105106107protected int doSelect(long timeout)108throws IOException109{110int entries = 0;111if (closed)112throw new ClosedSelectorException();113processDeregisterQueue();114try {115begin();116entries = kqueueWrapper.poll(timeout);117} finally {118end();119}120processDeregisterQueue();121return updateSelectedKeys(entries);122}123124/**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*/129private int updateSelectedKeys(int entries)130throws IOException131{132int numKeysUpdated = 0;133boolean interrupted = false;134135// A file descriptor may be registered with kqueue with more than one136// filter and so there may be more than one event for a fd. The update137// count in the MapEntry tracks when the fd was last updated and this138// ensures that the ready ops are updated rather than replaced by a139// second or subsequent event.140updateCount++;141142for (int i = 0; i < entries; i++) {143int nextFD = kqueueWrapper.getDescriptor(i);144if (nextFD == fd0) {145interrupted = true;146} else {147MapEntry me = fdMap.get(Integer.valueOf(nextFD));148149// entry is null in the case of an interrupt150if (me != null) {151int rOps = kqueueWrapper.getReventOps(i);152SelectionKeyImpl ski = me.ski;153if (selectedKeys.contains(ski)) {154// first time this file descriptor has been encountered on this155// update?156if (me.updateCount != updateCount) {157if (ski.channel.translateAndSetReadyOps(rOps, ski)) {158numKeysUpdated++;159me.updateCount = updateCount;160}161} else {162// ready ops have already been set on this update163ski.channel.translateAndUpdateReadyOps(rOps, ski);164}165} else {166ski.channel.translateAndSetReadyOps(rOps, ski);167if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {168selectedKeys.add(ski);169numKeysUpdated++;170me.updateCount = updateCount;171}172}173}174}175}176177if (interrupted) {178// Clear the wakeup pipe179synchronized (interruptLock) {180IOUtil.drain(fd0);181interruptTriggered = false;182}183}184return numKeysUpdated;185}186187188protected void implClose() throws IOException {189if (!closed) {190closed = true;191192// prevent further wakeup193synchronized (interruptLock) {194interruptTriggered = true;195}196197FileDispatcherImpl.closeIntFD(fd0);198FileDispatcherImpl.closeIntFD(fd1);199if (kqueueWrapper != null) {200kqueueWrapper.close();201kqueueWrapper = null;202selectedKeys = null;203204// Deregister channels205Iterator<SelectionKey> i = keys.iterator();206while (i.hasNext()) {207SelectionKeyImpl ski = (SelectionKeyImpl)i.next();208deregister(ski);209SelectableChannel selch = ski.channel();210if (!selch.isOpen() && !selch.isRegistered())211((SelChImpl)selch).kill();212i.remove();213}214totalChannels = 0;215}216fd0 = -1;217fd1 = -1;218}219}220221222protected void implRegister(SelectionKeyImpl ski) {223if (closed)224throw new ClosedSelectorException();225int fd = IOUtil.fdVal(ski.channel.getFD());226fdMap.put(Integer.valueOf(fd), new MapEntry(ski));227totalChannels++;228keys.add(ski);229}230231232protected void implDereg(SelectionKeyImpl ski) throws IOException {233int fd = ski.channel.getFDVal();234fdMap.remove(Integer.valueOf(fd));235kqueueWrapper.release(ski.channel);236totalChannels--;237keys.remove(ski);238selectedKeys.remove(ski);239deregister((AbstractSelectionKey)ski);240SelectableChannel selch = ski.channel();241if (!selch.isOpen() && !selch.isRegistered())242((SelChImpl)selch).kill();243}244245246public void putEventOps(SelectionKeyImpl ski, int ops) {247if (closed)248throw new ClosedSelectorException();249kqueueWrapper.setInterest(ski.channel, ops);250}251252253public Selector wakeup() {254synchronized (interruptLock) {255if (!interruptTriggered) {256kqueueWrapper.interrupt();257interruptTriggered = true;258}259}260return this;261}262}263264265