Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/classes/sun/nio/ch/EventPortWrapper.java
32288 views
/*1* Copyright (c) 2012, 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.HashMap;31import java.util.Map;3233import sun.misc.Unsafe;34import sun.security.action.GetIntegerAction;35import static sun.nio.ch.SolarisEventPort.*;3637/**38* Manages a Solaris event port and manipulates a native array of pollfd structs39* on Solaris.40*/4142class EventPortWrapper {43private static final Unsafe unsafe = Unsafe.getUnsafe();44private static final int addressSize = unsafe.addressSize();4546// Maximum number of open file descriptors47static final int OPEN_MAX = IOUtil.fdLimit();4849// Maximum number of events to retrive in one call to port_getn50static final int POLL_MAX = Math.min(OPEN_MAX-1, 1024);5152// initial size of the array to hold pending updates53private final int INITIAL_PENDING_UPDATE_SIZE = 256;5455// maximum size of updateArray56private static final int MAX_UPDATE_ARRAY_SIZE = AccessController.doPrivileged(57new GetIntegerAction("sun.nio.ch.maxUpdateArraySize", Math.min(OPEN_MAX, 64*1024)));5859// special update status to indicate that it should be ignored60private static final byte IGNORE = -1;6162// port file descriptor63private final int pfd;6465// the poll array (populated by port_getn)66private final long pollArrayAddress;67private final AllocatedNativeObject pollArray;6869// required when accessing the update* fields70private final Object updateLock = new Object();7172// the number of pending updates73private int updateCount;7475// queue of file descriptors with updates pending76private int[] updateDescriptors = new int[INITIAL_PENDING_UPDATE_SIZE];7778// events for file descriptors with registration changes pending, indexed79// by file descriptor and stored as bytes for efficiency reasons. For80// file descriptors higher than MAX_UPDATE_ARRAY_SIZE (unlimited case at81// least then the update is stored in a map.82private final byte[] eventsLow = new byte[MAX_UPDATE_ARRAY_SIZE];83private Map<Integer,Byte> eventsHigh;84// Used by release and updateRegistrations to track whether a file85// descriptor is registered with /dev/poll.86private final BitSet registered = new BitSet();8788// bit set to indicate if a file descriptor has been visited when89// processing updates (used to avoid duplicates calls to port_associate)90private BitSet visited = new BitSet();9192EventPortWrapper() throws IOException {93int allocationSize = POLL_MAX * SIZEOF_PORT_EVENT;94pollArray = new AllocatedNativeObject(allocationSize, true);95pollArrayAddress = pollArray.address();96this.pfd = port_create();97if (OPEN_MAX > MAX_UPDATE_ARRAY_SIZE)98eventsHigh = new HashMap<>();99}100101void close() throws IOException {102port_close(pfd);103pollArray.free();104}105106private short getSource(int i) {107int offset = SIZEOF_PORT_EVENT * i + OFFSETOF_SOURCE;108return pollArray.getShort(offset);109}110111int getEventOps(int i) {112int offset = SIZEOF_PORT_EVENT * i + OFFSETOF_EVENTS;113return pollArray.getInt(offset);114}115116int getDescriptor(int i) {117int offset = SIZEOF_PORT_EVENT * i + OFFSETOF_OBJECT;118if (addressSize == 4) {119return pollArray.getInt(offset);120} else {121return (int) pollArray.getLong(offset);122}123}124125private void setDescriptor(int i, int fd) {126int offset = SIZEOF_PORT_EVENT * i + OFFSETOF_OBJECT;127if (addressSize == 4) {128pollArray.putInt(offset, fd);129} else {130pollArray.putLong(offset, fd);131}132}133134private void setUpdate(int fd, byte events) {135if (fd < MAX_UPDATE_ARRAY_SIZE) {136eventsLow[fd] = events;137} else {138eventsHigh.put(Integer.valueOf(fd), Byte.valueOf(events));139}140}141142private byte getUpdate(int fd) {143if (fd < MAX_UPDATE_ARRAY_SIZE) {144return eventsLow[fd];145} else {146Byte result = eventsHigh.get(Integer.valueOf(fd));147// result should never be null148return result.byteValue();149}150}151152int poll(long timeout) throws IOException {153// update registrations prior to poll154synchronized (updateLock) {155156// process newest updates first157int i = updateCount - 1;158while (i >= 0) {159int fd = updateDescriptors[i];160if (!visited.get(fd)) {161short ev = getUpdate(fd);162if (ev != IGNORE) {163if (ev == 0) {164if (registered.get(fd)) {165port_dissociate(pfd, PORT_SOURCE_FD, (long)fd);166registered.clear(fd);167}168} else {169if (port_associate(pfd, PORT_SOURCE_FD, (long)fd, ev)) {170registered.set(fd);171}172}173174}175visited.set(fd);176}177i--;178}179updateCount = 0;180}181182// poll for events183int updated = port_getn(pfd, pollArrayAddress, POLL_MAX, timeout);184185// after polling we need to queue all polled file descriptors as they186// are candidates to register for the next poll.187synchronized (updateLock) {188for (int i=0; i<updated; i++) {189if (getSource(i) == PORT_SOURCE_USER) {190interrupted = true;191setDescriptor(i, -1);192} else {193// the default is to re-associate for the next poll194int fd = getDescriptor(i);195registered.clear(fd);196setInterest(fd);197}198}199}200201return updated;202}203204private void setInterest(int fd) {205assert Thread.holdsLock(updateLock);206207// record the file descriptor and events, expanding the208// respective arrays first if necessary.209int oldCapacity = updateDescriptors.length;210if (updateCount >= oldCapacity) {211int newCapacity = oldCapacity + INITIAL_PENDING_UPDATE_SIZE;212int[] newDescriptors = new int[newCapacity];213System.arraycopy(updateDescriptors, 0, newDescriptors, 0, oldCapacity);214updateDescriptors = newDescriptors;215}216updateDescriptors[updateCount++] = fd;217visited.clear(fd);218}219220void setInterest(int fd, int mask) {221synchronized (updateLock) {222setInterest(fd);223setUpdate(fd, (byte)mask);224assert getUpdate(fd) == mask;225}226}227228void release(int fd) {229synchronized (updateLock) {230if (registered.get(fd)) {231try {232port_dissociate(pfd, PORT_SOURCE_FD, (long)fd);233} catch (IOException ioe) {234throw new InternalError(ioe);235}236registered.clear(fd);237}238setUpdate(fd, IGNORE);239}240}241242// -- wakeup support --243244private boolean interrupted;245246public void interrupt() {247try {248port_send(pfd, 0);249} catch (IOException ioe) {250throw new InternalError(ioe);251}252}253254boolean interrupted() {255return interrupted;256}257258void clearInterrupted() {259interrupted = false;260}261}262263264