Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java
32288 views
/*1* Copyright (c) 2001, 2013, 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*/2425package sun.nio.ch;2627import java.io.IOException;28import java.security.AccessController;29import java.util.BitSet;30import java.util.Map;31import java.util.HashMap;32import sun.security.action.GetIntegerAction;333435/**36* Manipulates a native array of pollfd structs on Solaris:37*38* typedef struct pollfd {39* int fd;40* short events;41* short revents;42* } pollfd_t;43*44* @author Mike McCloskey45* @since 1.446*/4748class DevPollArrayWrapper {4950// Event masks51static final short POLLIN = 0x0001;52static final short POLLPRI = 0x0002;53static final short POLLOUT = 0x0004;54static final short POLLRDNORM = 0x0040;55static final short POLLWRNORM = POLLOUT;56static final short POLLRDBAND = 0x0080;57static final short POLLWRBAND = 0x0100;58static final short POLLNORM = POLLRDNORM;59static final short POLLERR = 0x0008;60static final short POLLHUP = 0x0010;61static final short POLLNVAL = 0x0020;62static final short POLLREMOVE = 0x0800;63static final short POLLCONN = POLLOUT;6465// Miscellaneous constants66static final short SIZE_POLLFD = 8;67static final short FD_OFFSET = 0;68static final short EVENT_OFFSET = 4;69static final short REVENT_OFFSET = 6;7071// Special value to indicate that an update should be ignored72static final byte IGNORE = (byte)-1;7374// Maximum number of open file descriptors75static final int OPEN_MAX = IOUtil.fdLimit();7677// Number of pollfd structures to create.78// dpwrite/ioctl(DP_POLL) allows up to OPEN_MAX-179static final int NUM_POLLFDS = Math.min(OPEN_MAX-1, 8192);8081// Initial size of arrays for fd registration changes82private static final int INITIAL_PENDING_UPDATE_SIZE = 64;8384// maximum size of updatesLow85private static final int MAX_UPDATE_ARRAY_SIZE = AccessController.doPrivileged(86new GetIntegerAction("sun.nio.ch.maxUpdateArraySize", Math.min(OPEN_MAX, 64*1024)));8788// The pollfd array for results from devpoll driver89private final AllocatedNativeObject pollArray;9091// Base address of the native pollArray92private final long pollArrayAddress;9394// The fd of the devpoll driver95private int wfd;9697// The fd of the interrupt line going out98private int outgoingInterruptFD;99100// The fd of the interrupt line coming in101private int incomingInterruptFD;102103// The index of the interrupt FD104private int interruptedIndex;105106// Number of updated pollfd entries107int updated;108109// object to synchronize fd registration changes110private final Object updateLock = new Object();111112// number of file descriptors with registration changes pending113private int updateCount;114115// file descriptors with registration changes pending116private int[] updateDescriptors = new int[INITIAL_PENDING_UPDATE_SIZE];117118// events for file descriptors with registration changes pending, indexed119// by file descriptor and stored as bytes for efficiency reasons. For120// file descriptors higher than MAX_UPDATE_ARRAY_SIZE (unlimited case at121// least then the update is stored in a map.122private final byte[] eventsLow = new byte[MAX_UPDATE_ARRAY_SIZE];123private Map<Integer,Byte> eventsHigh;124125// Used by release and updateRegistrations to track whether a file126// descriptor is registered with /dev/poll.127private final BitSet registered = new BitSet();128129DevPollArrayWrapper() {130int allocationSize = NUM_POLLFDS * SIZE_POLLFD;131pollArray = new AllocatedNativeObject(allocationSize, true);132pollArrayAddress = pollArray.address();133wfd = init();134if (OPEN_MAX > MAX_UPDATE_ARRAY_SIZE)135eventsHigh = new HashMap<>();136}137138void initInterrupt(int fd0, int fd1) {139outgoingInterruptFD = fd1;140incomingInterruptFD = fd0;141register(wfd, fd0, POLLIN);142}143144void putReventOps(int i, int revent) {145int offset = SIZE_POLLFD * i + REVENT_OFFSET;146pollArray.putShort(offset, (short)revent);147}148149int getEventOps(int i) {150int offset = SIZE_POLLFD * i + EVENT_OFFSET;151return pollArray.getShort(offset);152}153154int getReventOps(int i) {155int offset = SIZE_POLLFD * i + REVENT_OFFSET;156return pollArray.getShort(offset);157}158159int getDescriptor(int i) {160int offset = SIZE_POLLFD * i + FD_OFFSET;161return pollArray.getInt(offset);162}163164private void setUpdateEvents(int fd, byte events) {165if (fd < MAX_UPDATE_ARRAY_SIZE) {166eventsLow[fd] = events;167} else {168eventsHigh.put(Integer.valueOf(fd), Byte.valueOf(events));169}170}171172private byte getUpdateEvents(int fd) {173if (fd < MAX_UPDATE_ARRAY_SIZE) {174return eventsLow[fd];175} else {176Byte result = eventsHigh.get(Integer.valueOf(fd));177// result should never be null178return result.byteValue();179}180}181182void setInterest(int fd, int mask) {183synchronized (updateLock) {184// record the file descriptor and events, expanding the185// respective arrays first if necessary.186int oldCapacity = updateDescriptors.length;187if (updateCount == oldCapacity) {188int newCapacity = oldCapacity + INITIAL_PENDING_UPDATE_SIZE;189int[] newDescriptors = new int[newCapacity];190System.arraycopy(updateDescriptors, 0, newDescriptors, 0, oldCapacity);191updateDescriptors = newDescriptors;192}193updateDescriptors[updateCount++] = fd;194195// events are stored as bytes for efficiency reasons196byte b = (byte)mask;197assert (b == mask) && (b != IGNORE);198setUpdateEvents(fd, b);199}200}201202void release(int fd) {203synchronized (updateLock) {204// ignore any pending update for this file descriptor205setUpdateEvents(fd, IGNORE);206207// remove from /dev/poll208if (registered.get(fd)) {209register(wfd, fd, POLLREMOVE);210registered.clear(fd);211}212}213}214215void closeDevPollFD() throws IOException {216FileDispatcherImpl.closeIntFD(wfd);217pollArray.free();218}219220int poll(long timeout) throws IOException {221updateRegistrations();222updated = poll0(pollArrayAddress, NUM_POLLFDS, timeout, wfd);223for (int i=0; i<updated; i++) {224if (getDescriptor(i) == incomingInterruptFD) {225interruptedIndex = i;226interrupted = true;227break;228}229}230return updated;231}232233void updateRegistrations() throws IOException {234synchronized (updateLock) {235// Populate pollfd array with updated masks236int j = 0;237int index = 0;238while (j < updateCount) {239int fd = updateDescriptors[j];240short events = getUpdateEvents(fd);241boolean wasRegistered = registered.get(fd);242243// events = 0 => POLLREMOVE or do-nothing244if (events != IGNORE) {245if (events == 0) {246if (wasRegistered) {247events = POLLREMOVE;248registered.clear(fd);249} else {250events = IGNORE;251}252} else {253if (!wasRegistered) {254registered.set(fd);255}256}257}258259// populate pollfd array with updated event260if (events != IGNORE) {261// insert POLLREMOVE if changing events262if (wasRegistered && events != POLLREMOVE) {263putPollFD(pollArray, index, fd, POLLREMOVE);264index++;265}266putPollFD(pollArray, index, fd, events);267index++;268if (index >= (NUM_POLLFDS-1)) {269registerMultiple(wfd, pollArray.address(), index);270index = 0;271}272273// events for this fd now up to date274setUpdateEvents(fd, IGNORE);275}276j++;277}278279// write any remaining updates280if (index > 0)281registerMultiple(wfd, pollArray.address(), index);282283updateCount = 0;284}285}286287private void putPollFD(AllocatedNativeObject array, int index, int fd,288short event)289{290int structIndex = SIZE_POLLFD * index;291array.putInt(structIndex + FD_OFFSET, fd);292array.putShort(structIndex + EVENT_OFFSET, event);293array.putShort(structIndex + REVENT_OFFSET, (short)0);294}295296boolean interrupted = false;297298public void interrupt() {299interrupt(outgoingInterruptFD);300}301302public int interruptedIndex() {303return interruptedIndex;304}305306boolean interrupted() {307return interrupted;308}309310void clearInterrupted() {311interrupted = false;312}313314private native int init();315private native void register(int wfd, int fd, int mask);316private native void registerMultiple(int wfd, long address, int len)317throws IOException;318private native int poll0(long pollAddress, int numfds, long timeout,319int wfd);320private static native void interrupt(int fd);321322static {323IOUtil.load();324}325}326327328