1 /* 2 * Copyright (c) 2001, 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 package sun.nio.ch; 27 28 import java.io.IOException; 29 import java.security.AccessController; 30 import java.util.BitSet; 31 import java.util.Map; 32 import java.util.HashMap; 33 import sun.security.action.GetIntegerAction; 34 35 36 /** 37 * Manipulates a native array of pollfd structs on Solaris: 38 * 39 * typedef struct pollfd { 40 * int fd; 41 * short events; 42 * short revents; 43 * } pollfd_t; 44 * 45 * @author Mike McCloskey 46 * @since 1.4 47 */ 48 49 class DevPollArrayWrapper { 50 51 // Event masks 52 static final short POLLIN = 0x0001; 53 static final short POLLPRI = 0x0002; 54 static final short POLLOUT = 0x0004; 55 static final short POLLRDNORM = 0x0040; 56 static final short POLLWRNORM = POLLOUT; 57 static final short POLLRDBAND = 0x0080; 58 static final short POLLWRBAND = 0x0100; 59 static final short POLLNORM = POLLRDNORM; 60 static final short POLLERR = 0x0008; 61 static final short POLLHUP = 0x0010; 62 static final short POLLNVAL = 0x0020; 63 static final short POLLREMOVE = 0x0800; 64 static final short POLLCONN = POLLOUT; 65 66 // Miscellaneous constants 67 static final short SIZE_POLLFD = 8; 68 static final short FD_OFFSET = 0; 69 static final short EVENT_OFFSET = 4; 70 static final short REVENT_OFFSET = 6; 71 72 // Special value to indicate that an update should be ignored 73 static final byte IGNORE = (byte)-1; 74 75 // Maximum number of open file descriptors 76 static final int OPEN_MAX = IOUtil.fdLimit(); 77 78 // Number of pollfd structures to create. 79 // dpwrite/ioctl(DP_POLL) allows up to OPEN_MAX-1 80 static final int NUM_POLLFDS = Math.min(OPEN_MAX-1, 8192); 81 82 // Initial size of arrays for fd registration changes 83 private static final int INITIAL_PENDING_UPDATE_SIZE = 64; 84 85 // maximum size of updatesLow 86 private static final int MAX_UPDATE_ARRAY_SIZE = AccessController.doPrivileged( 87 new GetIntegerAction("sun.nio.ch.maxUpdateArraySize", Math.min(OPEN_MAX, 64*1024))); 88 89 // The pollfd array for results from devpoll driver 90 private final AllocatedNativeObject pollArray; 91 92 // Base address of the native pollArray 93 private final long pollArrayAddress; 94 95 // The fd of the devpoll driver 96 private int wfd; 97 98 // The fd of the interrupt line going out 99 private int outgoingInterruptFD; 100 101 // The fd of the interrupt line coming in 102 private int incomingInterruptFD; 103 104 // The index of the interrupt FD 105 private int interruptedIndex; 106 107 // Number of updated pollfd entries 108 int updated; 109 110 // object to synchronize fd registration changes 111 private final Object updateLock = new Object(); 112 113 // number of file descriptors with registration changes pending 114 private int updateCount; 115 116 // file descriptors with registration changes pending 117 private int[] updateDescriptors = new int[INITIAL_PENDING_UPDATE_SIZE]; 118 119 // events for file descriptors with registration changes pending, indexed 120 // by file descriptor and stored as bytes for efficiency reasons. For 121 // file descriptors higher than MAX_UPDATE_ARRAY_SIZE (unlimited case at 122 // least then the update is stored in a map. 123 private final byte[] eventsLow = new byte[MAX_UPDATE_ARRAY_SIZE]; 124 private Map<Integer,Byte> eventsHigh; 125 126 // Used by release and updateRegistrations to track whether a file 127 // descriptor is registered with /dev/poll. 128 private final BitSet registered = new BitSet(); 129 130 DevPollArrayWrapper() { 131 int allocationSize = NUM_POLLFDS * SIZE_POLLFD; 132 pollArray = new AllocatedNativeObject(allocationSize, true); 133 pollArrayAddress = pollArray.address(); 134 wfd = init(); 135 if (OPEN_MAX > MAX_UPDATE_ARRAY_SIZE) 136 eventsHigh = new HashMap<>(); 137 } 138 139 void initInterrupt(int fd0, int fd1) { 140 outgoingInterruptFD = fd1; 141 incomingInterruptFD = fd0; 142 register(wfd, fd0, POLLIN); 143 } 144 145 void putReventOps(int i, int revent) { 146 int offset = SIZE_POLLFD * i + REVENT_OFFSET; 147 pollArray.putShort(offset, (short)revent); 148 } 149 150 int getEventOps(int i) { 151 int offset = SIZE_POLLFD * i + EVENT_OFFSET; 152 return pollArray.getShort(offset); 153 } 154 155 int getReventOps(int i) { 156 int offset = SIZE_POLLFD * i + REVENT_OFFSET; 157 return pollArray.getShort(offset); 158 } 159 160 int getDescriptor(int i) { 161 int offset = SIZE_POLLFD * i + FD_OFFSET; 162 return pollArray.getInt(offset); 163 } 164 165 private void setUpdateEvents(int fd, byte events) { 166 if (fd < MAX_UPDATE_ARRAY_SIZE) { 167 eventsLow[fd] = events; 168 } else { 169 eventsHigh.put(Integer.valueOf(fd), Byte.valueOf(events)); 170 } 171 } 172 173 private byte getUpdateEvents(int fd) { 174 if (fd < MAX_UPDATE_ARRAY_SIZE) { 175 return eventsLow[fd]; 176 } else { 177 Byte result = eventsHigh.get(Integer.valueOf(fd)); 178 // result should never be null 179 return result.byteValue(); 180 } 181 } 182 183 void setInterest(int fd, int mask) { 184 synchronized (updateLock) { 185 // record the file descriptor and events, expanding the 186 // respective arrays first if necessary. 187 int oldCapacity = updateDescriptors.length; 188 if (updateCount == oldCapacity) { 189 int newCapacity = oldCapacity + INITIAL_PENDING_UPDATE_SIZE; 190 int[] newDescriptors = new int[newCapacity]; 191 System.arraycopy(updateDescriptors, 0, newDescriptors, 0, oldCapacity); 192 updateDescriptors = newDescriptors; 193 } 194 updateDescriptors[updateCount++] = fd; 195 196 // events are stored as bytes for efficiency reasons 197 byte b = (byte)mask; 198 assert (b == mask) && (b != IGNORE); 199 setUpdateEvents(fd, b); 200 } 201 } 202 203 void release(int fd) { 204 synchronized (updateLock) { 205 // ignore any pending update for this file descriptor 206 setUpdateEvents(fd, IGNORE); 207 208 // remove from /dev/poll 209 if (registered.get(fd)) { 210 register(wfd, fd, POLLREMOVE); 211 registered.clear(fd); 212 } 213 } 214 } 215 216 void close() throws IOException { 217 FileDispatcherImpl.closeIntFD(wfd); 218 pollArray.free(); 219 } 220 221 int poll(long timeout) throws IOException { 222 updateRegistrations(); 223 updated = poll0(pollArrayAddress, NUM_POLLFDS, timeout, wfd); 224 for (int i=0; i<updated; i++) { 225 if (getDescriptor(i) == incomingInterruptFD) { 226 interruptedIndex = i; 227 interrupted = true; 228 break; 229 } 230 } 231 return updated; 232 } 233 234 void updateRegistrations() throws IOException { 235 synchronized (updateLock) { 236 // Populate pollfd array with updated masks 237 int j = 0; 238 int index = 0; 239 while (j < updateCount) { 240 int fd = updateDescriptors[j]; 241 short events = getUpdateEvents(fd); 242 boolean wasRegistered = registered.get(fd); 243 244 // events = 0 => POLLREMOVE or do-nothing 245 if (events != IGNORE) { 246 if (events == 0) { 247 if (wasRegistered) { 248 events = POLLREMOVE; 249 registered.clear(fd); 250 } else { 251 events = IGNORE; 252 } 253 } else { 254 if (!wasRegistered) { 255 registered.set(fd); 256 } 257 } 258 } 259 260 // populate pollfd array with updated event 261 if (events != IGNORE) { 262 // insert POLLREMOVE if changing events 263 if (wasRegistered && events != POLLREMOVE) { 264 putPollFD(pollArray, index, fd, POLLREMOVE); 265 index++; 266 } 267 putPollFD(pollArray, index, fd, events); 268 index++; 269 if (index >= (NUM_POLLFDS-1)) { 270 registerMultiple(wfd, pollArray.address(), index); 271 index = 0; 272 } 273 274 // events for this fd now up to date 275 setUpdateEvents(fd, IGNORE); 276 } 277 j++; 278 } 279 280 // write any remaining updates 281 if (index > 0) 282 registerMultiple(wfd, pollArray.address(), index); 283 284 updateCount = 0; 285 } 286 } 287 288 private void putPollFD(AllocatedNativeObject array, int index, int fd, 289 short event) 290 { 291 int structIndex = SIZE_POLLFD * index; 292 array.putInt(structIndex + FD_OFFSET, fd); 293 array.putShort(structIndex + EVENT_OFFSET, event); 294 array.putShort(structIndex + REVENT_OFFSET, (short)0); 295 } 296 297 boolean interrupted = false; 298 299 public void interrupt() { 300 interrupt(outgoingInterruptFD); 301 } 302 303 public int interruptedIndex() { 304 return interruptedIndex; 305 } 306 307 boolean interrupted() { 308 return interrupted; 309 } 310 311 void clearInterrupted() { 312 interrupted = false; 313 } 314 315 private native int init(); 316 private native void register(int wfd, int fd, int mask); 317 private native void registerMultiple(int wfd, long address, int len) 318 throws IOException; 319 private native int poll0(long pollAddress, int numfds, long timeout, 320 int wfd); 321 private static native void interrupt(int fd); 322 323 static { 324 IOUtil.load(); 325 } 326 }