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